Files
Cielonos/Assets/Scripts/MainGame/UI/Common/ConfirmPage/ConfirmUIPage.cs
SoulliesOfficial 6d7ebc5825 Passion & UI
2026-06-12 17:11:39 -04:00

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();
}
}
}