197 lines
6.4 KiB
C#
197 lines
6.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using DG.Tweening;
|
|
using SLSUtilities.UI;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Cielonos.MainGame.UI
|
|
{
|
|
/// <summary>
|
|
/// 通用确认 / 信息提示页面。
|
|
/// <para>
|
|
/// 作为动态 Prefab 实例化,使用完毕后自动销毁。
|
|
/// 通过 <see cref="Show"/> 静态方法创建并显示。
|
|
/// </para>
|
|
/// <para>
|
|
/// 支持任意数量的按钮:
|
|
/// - 两个按钮(确认 / 取消)用于需要用户确认的场景。
|
|
/// - 单个按钮(确定)用于信息提示场景。
|
|
/// </para>
|
|
/// </summary>
|
|
[RequireComponent(typeof(CanvasGroup))]
|
|
public class ConfirmUIPage : UIPageBase
|
|
{
|
|
// ──────────────────── 常量 ────────────────────
|
|
private const float FadeInDuration = 0.2f;
|
|
private const float FadeOutDuration = 0.15f;
|
|
|
|
// ──────────────────── 序列化引用 ────────────────────
|
|
[Header("Content")]
|
|
[SerializeField] private TMP_Text titleText;
|
|
[SerializeField] private TMP_Text descriptionText;
|
|
|
|
[Header("Buttons")]
|
|
[SerializeField] private Transform buttonContainer;
|
|
[SerializeField] private Button buttonPrefab;
|
|
|
|
// ──────────────────── 运行时状态 ────────────────────
|
|
private readonly List<Button> spawnedButtons = new();
|
|
private Action pendingCallback;
|
|
private bool allowEscClose = true;
|
|
|
|
/// <inheritdoc/>
|
|
public override bool CloseOnEsc => allowEscClose;
|
|
|
|
protected override void Start()
|
|
{
|
|
|
|
}
|
|
|
|
// ──────────────────── 静态入口 ────────────────────
|
|
|
|
/// <summary>
|
|
/// 创建并显示一个确认页面实例。
|
|
/// </summary>
|
|
/// <param name="config">页面配置,包含标题、描述和按钮。</param>
|
|
/// <returns>已创建的页面实例。</returns>
|
|
public static ConfirmUIPage Show(ConfirmPageConfig config)
|
|
{
|
|
if (config == null)
|
|
throw new ArgumentNullException(nameof(config));
|
|
|
|
var manager = UIPageManager.Instance;
|
|
var go = manager.InstantiateDynamicPage(manager.ConfirmPagePrefab);
|
|
var page = go.GetComponent<ConfirmUIPage>();
|
|
|
|
if (page == null)
|
|
{
|
|
Debug.LogError("[ConfirmUIPage] Prefab is missing ConfirmUIPage component.");
|
|
Destroy(go);
|
|
return null;
|
|
}
|
|
|
|
page.Initialize(config);
|
|
page.Open();
|
|
return page;
|
|
}
|
|
|
|
// ──────────────────── 初始化 ────────────────────
|
|
|
|
/// <summary>
|
|
/// 根据配置初始化页面内容和按钮。
|
|
/// </summary>
|
|
private void Initialize(ConfirmPageConfig config)
|
|
{
|
|
allowEscClose = config.AllowEscClose;
|
|
|
|
if (titleText != null)
|
|
titleText.text = config.Title;
|
|
|
|
if (descriptionText != null)
|
|
descriptionText.text = config.Description;
|
|
|
|
CreateButtons(config.Buttons);
|
|
}
|
|
|
|
private void CreateButtons(List<ConfirmButtonConfig> buttonConfigs)
|
|
{
|
|
if (buttonPrefab == null)
|
|
{
|
|
Debug.LogError("[ConfirmUIPage] buttonPrefab is not assigned.");
|
|
return;
|
|
}
|
|
|
|
// 隐藏模板按钮
|
|
buttonPrefab.gameObject.SetActive(false);
|
|
|
|
foreach (var btnConfig in buttonConfigs)
|
|
{
|
|
var button = Instantiate(buttonPrefab, buttonContainer);
|
|
button.gameObject.SetActive(true);
|
|
|
|
var label = button.GetComponentInChildren<TMP_Text>();
|
|
if (label != null)
|
|
label.text = btnConfig.Label;
|
|
|
|
var callback = btnConfig.OnClick;
|
|
button.onClick.AddListener(() => OnButtonClicked(callback));
|
|
|
|
spawnedButtons.Add(button);
|
|
}
|
|
}
|
|
|
|
// ──────────────────── 生命周期 ────────────────────
|
|
|
|
public override void Open()
|
|
{
|
|
if (IsOpen) return;
|
|
IsOpen = true;
|
|
|
|
gameObject.SetActive(true);
|
|
canvasGroup.alpha = 0f;
|
|
canvasGroup.interactable = false;
|
|
canvasGroup.blocksRaycasts = false;
|
|
|
|
UIPageManager.Instance.RegisterPage(this);
|
|
|
|
canvasGroup.DOFade(1f, FadeInDuration)
|
|
.SetUpdate(true)
|
|
.OnComplete(() =>
|
|
{
|
|
canvasGroup.interactable = true;
|
|
canvasGroup.blocksRaycasts = true;
|
|
OnPageOpened();
|
|
}).Play();
|
|
}
|
|
|
|
public override void Close()
|
|
{
|
|
if (!IsOpen) return;
|
|
IsOpen = false;
|
|
|
|
UIPageManager.Instance.UnregisterPage(this);
|
|
canvasGroup.interactable = false;
|
|
canvasGroup.blocksRaycasts = false;
|
|
|
|
canvasGroup.DOFade(0f, FadeOutDuration)
|
|
.SetUpdate(true)
|
|
.OnComplete(() =>
|
|
{
|
|
OnPageClosed();
|
|
Destroy(gameObject);
|
|
}).Play();
|
|
}
|
|
|
|
protected override void OnPageClosed()
|
|
{
|
|
// 先触发基类事件
|
|
base.OnPageClosed();
|
|
|
|
// 执行挂起的按钮回调
|
|
var callback = pendingCallback;
|
|
pendingCallback = null;
|
|
callback?.Invoke();
|
|
|
|
// 清理按钮监听
|
|
foreach (var btn in spawnedButtons)
|
|
{
|
|
if (btn != null)
|
|
btn.onClick.RemoveAllListeners();
|
|
}
|
|
|
|
spawnedButtons.Clear();
|
|
}
|
|
|
|
// ──────────────────── 按钮处理 ────────────────────
|
|
|
|
private void OnButtonClicked(Action callback)
|
|
{
|
|
if (!IsOpen) return;
|
|
pendingCallback = callback;
|
|
Close();
|
|
}
|
|
}
|
|
}
|