2025-09-04 14:23:51 +08:00
|
|
|
|
using System;
|
2025-12-27 16:34:21 +08:00
|
|
|
|
using Cysharp.Threading.Tasks;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
using Framework;
|
|
|
|
|
|
using PhxhSDK;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/*
|
|
|
|
|
|
╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
|
|
|
|
|
║ UIWindow 按钮绑定模块 (Button Binding) ║
|
|
|
|
|
|
╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【模块功能】 ║
|
|
|
|
|
|
║ 本模块提供了两大核心功能: ║
|
|
|
|
|
|
║ 1. 手动按钮绑定 API - 在OnInit()中手动绑定自定义按钮 ║
|
|
|
|
|
|
║ 2. 默认按钮自动绑定 - 约定节点名自动绑定常用按钮(关闭、回主界面、返回) ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【使用方式】 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
|
|
|
|
|
|
║ │ 方式一:使用默认按钮(推荐) │ ║
|
|
|
|
|
|
║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 只需在预制体中创建约定名称的按钮节点,框架会自动绑定: ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔴 关闭按钮: ║
|
|
|
|
|
|
║ 节点名:BgClose(背景关闭)或 BtnClose(标题栏关闭) ║
|
|
|
|
|
|
║ 默认行为:关闭并销毁窗口 CloseWindow(true) ║
|
|
|
|
|
|
║ 重写方法:OnCloseClick() ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🏠 回主界面按钮: ║
|
|
|
|
|
|
║ 节点名:BtnHome、BtnBackHome 或 HomeButton ║
|
|
|
|
|
|
║ 默认行为:关闭当前窗口 + 打开主界面 ║
|
|
|
|
|
|
║ 重写方法:OnHomeClick() ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ ⬅️ 返回按钮: ║
|
|
|
|
|
|
║ 节点名:BtnBack、BackButton 或 BtnReturn ║
|
|
|
|
|
|
║ 默认行为:调用 Back() → 触发 OnBack() → 使用 BackStrategy ║
|
|
|
|
|
|
║ 重写方法:OnBack() (async) ║
|
|
|
|
|
|
║ 特点:与返回键(Android Back/ESC)行为完全一致 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 示例: ║
|
|
|
|
|
|
║ public class MyWindow : UIWindow ║
|
|
|
|
|
|
║ { ║
|
|
|
|
|
|
║ // 无需任何代码,自动绑定 ║
|
|
|
|
|
|
║ } ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
|
|
|
|
|
|
║ │ 方式二:手动绑定自定义按钮 │ ║
|
|
|
|
|
|
║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 在 OnInit() 中使用 BindButton() API 手动绑定: ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 示例: ║
|
|
|
|
|
|
║ protected override void OnInit() ║
|
|
|
|
|
|
║ { ║
|
|
|
|
|
|
║ // 通过路径绑定 ║
|
|
|
|
|
|
║ BindButton("BtnStart", OnStartClick); ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ // 通过Button组件绑定 ║
|
|
|
|
|
|
║ BindButton(myButton, OnMyButtonClick); ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ // 带参数绑定 ║
|
|
|
|
|
|
║ BindButton(itemButton, OnItemClick, itemData); ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ // 静音绑定(不播放音效) ║
|
|
|
|
|
|
║ BindButton(silentButton, OnSilentClick, playAudio: false); ║
|
|
|
|
|
|
║ } ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║
|
|
|
|
|
|
║ │ 方式三:自定义默认按钮 │ ║
|
|
|
|
|
|
║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 重写虚属性或虚方法自定义默认按钮: ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 示例: ║
|
|
|
|
|
|
║ public class CustomWindow : UIWindow ║
|
|
|
|
|
|
║ { ║
|
|
|
|
|
|
║ // 自定义节点名 ║
|
|
|
|
|
|
║ protected override string[] DefaultCloseButtonNames => new[] { "MyCloseBtn" }; ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ // 自定义关闭逻辑 ║
|
|
|
|
|
|
║ protected override void OnCloseClick() ║
|
|
|
|
|
|
║ { ║
|
|
|
|
|
|
║ ShowConfirmDialog("确定关闭?", () => CloseWindow(true)); ║
|
|
|
|
|
|
║ } ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ // 自定义返回逻辑(与返回键行为一致) ║
|
|
|
|
|
|
║ protected override async UniTask<bool> OnBack() ║
|
|
|
|
|
|
║ { ║
|
|
|
|
|
|
║ SaveCurrentState(); ║
|
|
|
|
|
|
║ CloseWindow(false); ║
|
|
|
|
|
|
║ return true; ║
|
|
|
|
|
|
║ } ║
|
|
|
|
|
|
║ } ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【更多信息】 ║
|
|
|
|
|
|
║ 详细使用指南请参考:Assets/Code/Scripts/Framework/UI/README_DefaultButtons.md ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// UI窗口基类 - 按钮绑定部分
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// 提供按钮绑定API和默认按钮自动绑定功能
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract partial class UIWindow
|
|
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
#region Button Binding Core - 按钮绑定核心逻辑
|
|
|
|
|
|
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 处理按钮点击的音频逻辑
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void HandleButtonAudio(Button button, bool playAudio)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!playAudio) return;
|
|
|
|
|
|
|
|
|
|
|
|
var clickAudio = button.GetComponent<ClickAudio>();
|
|
|
|
|
|
if (clickAudio)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (clickAudio.IsPlayAudio && !string.IsNullOrEmpty(clickAudio.AudioKey))
|
|
|
|
|
|
{
|
|
|
|
|
|
AudioManager.Instance.PlayAudio(clickAudio.AudioKey);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
CommonUtilsFramework.PlayUICommonSound();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// 绑定按钮点击事件的核心逻辑(无参数)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void BindButtonCore(Button button, Action action, bool playAudio = true)
|
|
|
|
|
|
{
|
2025-10-23 15:43:50 +08:00
|
|
|
|
if (button is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("传入按钮为空,无法绑定点击事件!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-04 14:23:51 +08:00
|
|
|
|
|
|
|
|
|
|
button.onClick.RemoveAllListeners();
|
|
|
|
|
|
button.onClick.AddListener(() =>
|
|
|
|
|
|
{
|
2025-10-23 15:43:50 +08:00
|
|
|
|
DebugUtil.Log("按钮被点击: {0}", button.gameObject.name);
|
2025-09-12 15:18:50 +08:00
|
|
|
|
if (UIManager.IsUIInputBlocked) return;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
UIManager.Instance.BlockUIForNormalOperation();
|
2025-09-04 14:23:51 +08:00
|
|
|
|
HandleButtonAudio(button, playAudio);
|
|
|
|
|
|
action?.Invoke();
|
|
|
|
|
|
});
|
2025-10-23 15:43:50 +08:00
|
|
|
|
|
|
|
|
|
|
DebugUtil.Log("按钮绑定完成: {0}", button.gameObject.name);
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绑定按钮点击事件的核心逻辑(带参数)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void BindButtonCore<T>(Button button, Action<T> action, T parameter, bool playAudio = true)
|
|
|
|
|
|
{
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (button is null) return;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
|
|
|
|
|
|
button.onClick.RemoveAllListeners();
|
|
|
|
|
|
button.onClick.AddListener(() =>
|
|
|
|
|
|
{
|
2025-09-12 15:18:50 +08:00
|
|
|
|
if (UIManager.IsUIInputBlocked) return;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
UIManager.Instance.BlockUIForNormalOperation();
|
2025-09-04 14:23:51 +08:00
|
|
|
|
HandleButtonAudio(button, playAudio);
|
|
|
|
|
|
|
|
|
|
|
|
if (parameter == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("=== 传入参数为空! ===");
|
|
|
|
|
|
}
|
|
|
|
|
|
action?.Invoke(parameter);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-27 16:34:21 +08:00
|
|
|
|
#region Button Binding Public API - 手动绑定按钮的公共API
|
2025-09-04 14:23:51 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 通过路径绑定按钮
|
|
|
|
|
|
/// </summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="target">按钮节点路径(相对于窗口根节点)</param>
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// <param name="action">点击回调</param>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="playAudio">是否播放点击音效(默认true)</param>
|
|
|
|
|
|
/// <returns>Button组件</returns>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// BindButton("TopBar/BtnSettings", OnSettingsClick);
|
|
|
|
|
|
/// </example>
|
2025-09-04 14:23:51 +08:00
|
|
|
|
public Button BindButton(string target, Action action, bool playAudio = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
GameObject obj = transform.Find(target)?.gameObject;
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (obj is not null)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
Button button = obj.GetComponent<Button>();
|
|
|
|
|
|
BindButtonCore(button, action, playAudio);
|
|
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
DebugUtil.LogError("未找到按钮节点: {0}/{1}", gameObject.name, target);
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// 直接绑定Button组件
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// </summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="button">Button组件</param>
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// <param name="action">点击回调</param>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="playAudio">是否播放点击音效(默认true)</param>
|
|
|
|
|
|
/// <returns>Button组件</returns>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// BindButton(myButton, OnMyButtonClick);
|
|
|
|
|
|
/// </example>
|
|
|
|
|
|
public Button BindButton(Button button, Action action, bool playAudio = true)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
if (button is not null)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
BindButtonCore(button, action, playAudio);
|
2025-09-04 14:23:51 +08:00
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
DebugUtil.LogError("传入按钮为空,请检查按钮绑定参数!");
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
2025-12-27 16:34:21 +08:00
|
|
|
|
return button;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// 通过GameObject绑定按钮(带参数)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// </summary>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <typeparam name="T">参数类型</typeparam>
|
|
|
|
|
|
/// <param name="obj">按钮GameObject</param>
|
2025-09-04 14:23:51 +08:00
|
|
|
|
/// <param name="action">点击回调</param>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="parameter">回调参数</param>
|
|
|
|
|
|
/// <param name="playAudio">是否播放点击音效(默认true)</param>
|
|
|
|
|
|
/// <returns>Button组件</returns>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// BindButton(itemObj, OnItemClick, itemData);
|
|
|
|
|
|
/// </example>
|
|
|
|
|
|
public Button BindButton<T>(GameObject obj, Action<T> action, T parameter, bool playAudio = true)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
if (obj is not null)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
Button button = obj.GetComponent<Button>();
|
|
|
|
|
|
BindButtonCore(button, action, parameter, playAudio);
|
2025-09-04 14:23:51 +08:00
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
DebugUtil.LogError("传入GameObject为空,请检查按钮绑定参数!");
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
2025-12-27 16:34:21 +08:00
|
|
|
|
return null;
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 直接绑定Button组件(带参数)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">参数类型</typeparam>
|
|
|
|
|
|
/// <param name="button">Button组件</param>
|
|
|
|
|
|
/// <param name="action">点击回调</param>
|
|
|
|
|
|
/// <param name="parameter">回调参数</param>
|
2025-12-27 16:34:21 +08:00
|
|
|
|
/// <param name="playAudio">是否播放点击音效(默认true)</param>
|
|
|
|
|
|
/// <returns>Button组件</returns>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// BindButton(itemButton, OnItemClick, itemData);
|
|
|
|
|
|
/// </example>
|
2025-09-04 14:23:51 +08:00
|
|
|
|
public Button BindButton<T>(Button button, Action<T> action, T parameter, bool playAudio = true)
|
|
|
|
|
|
{
|
2025-09-13 16:51:11 +08:00
|
|
|
|
if (button is not null)
|
2025-09-04 14:23:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
BindButtonCore(button, action, parameter, playAudio);
|
|
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-27 16:34:21 +08:00
|
|
|
|
DebugUtil.LogError("传入按钮为空,请检查按钮绑定参数!");
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-12-27 16:34:21 +08:00
|
|
|
|
|
|
|
|
|
|
#region Default Close Button - 默认关闭按钮自动绑定
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 默认关闭按钮的节点名配置(子类可重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 默认支持的节点名:
|
|
|
|
|
|
/// - BgClose: 背景关闭按钮(最常用,点击背景关闭)
|
|
|
|
|
|
/// - BtnClose: 标题栏关闭按钮(通常在右上角)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 自定义示例:
|
|
|
|
|
|
/// protected override string[] DefaultCloseButtonNames => new[] { "MyCloseBtn", "Btn_Exit" };
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual string[] DefaultCloseButtonNames => new[] { "BgClose", "BtnClose" };
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绑定所有配置的默认关闭按钮
|
|
|
|
|
|
/// 在 DoInit() 阶段自动调用,无需手动调用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void BindDefaultCloseButtons()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var buttonName in DefaultCloseButtonNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
TryBindCloseButton(buttonName, OnCloseClick);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试绑定关闭按钮
|
|
|
|
|
|
/// 如果节点不存在,不会报错,只是不绑定
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TryBindCloseButton(string nodeName, Action callback)
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = transform.Find(nodeName);
|
|
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
var btn = trans.GetComponent<Button>();
|
|
|
|
|
|
if (btn)
|
|
|
|
|
|
{
|
|
|
|
|
|
BindButton(btn, callback);
|
|
|
|
|
|
DebugUtil.Log("✅ 已自动绑定关闭按钮: {0} -> {1}", WindowName, nodeName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 关闭按钮点击回调(虚方法,子类可重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 默认行为:
|
|
|
|
|
|
/// - 关闭并销毁窗口 CloseWindow(true)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 自定义示例:
|
|
|
|
|
|
/// protected override void OnCloseClick()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// // 显示确认对话框
|
|
|
|
|
|
/// ShowConfirmDialog("确定关闭?", () => CloseWindow(true));
|
|
|
|
|
|
/// }
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 或者仅隐藏不销毁:
|
|
|
|
|
|
/// protected override void OnCloseClick()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// CloseWindow(false); // 保留在内存,快速重开
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual void OnCloseClick()
|
|
|
|
|
|
{
|
|
|
|
|
|
CloseWindow(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Default Home Button - 默认回主界面按钮自动绑定
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 默认回主界面按钮的节点名配置(子类可重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 默认支持的节点名:
|
|
|
|
|
|
/// - BtnHome: 回主界面按钮(推荐,常用)
|
|
|
|
|
|
/// - BtnBackHome: 返回主界面按钮
|
|
|
|
|
|
/// - HomeButton: 主页按钮
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 自定义示例:
|
|
|
|
|
|
/// protected override string[] DefaultHomeButtonNames => new[] { "MainMenuBtn" };
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual string[] DefaultHomeButtonNames => new[] { "BtnHome", "BtnBackHome", "HomeButton" };
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绑定所有配置的默认回主界面按钮
|
|
|
|
|
|
/// 在 DoInit() 阶段自动调用,无需手动调用
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void BindDefaultHomeButtons()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var buttonName in DefaultHomeButtonNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
TryBindHomeButton(buttonName, OnHomeClick);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试绑定回主界面按钮
|
|
|
|
|
|
/// 如果节点不存在,不会报错,只是不绑定
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TryBindHomeButton(string nodeName, Action callback)
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = transform.Find(nodeName);
|
|
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
var btn = trans.GetComponent<Button>();
|
|
|
|
|
|
if (btn)
|
|
|
|
|
|
{
|
|
|
|
|
|
BindButton(btn, callback);
|
|
|
|
|
|
DebugUtil.Log("✅ 已自动绑定回主界面按钮: {0} -> {1}", WindowName, nodeName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 回主界面按钮点击回调(虚方法,子类可重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 默认行为:
|
|
|
|
|
|
/// 1. 关闭当前窗口 CloseWindow(true)
|
|
|
|
|
|
/// 2. 打开主界面 UIManager.Instance.CreateAndOpenWindow(UINameConst.UI_MainPanel)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 自定义示例:
|
|
|
|
|
|
/// protected override void OnHomeClick()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// // 清理数据
|
|
|
|
|
|
/// CleanupGameData();
|
|
|
|
|
|
///
|
|
|
|
|
|
/// // 调用基类方法
|
|
|
|
|
|
/// base.OnHomeClick();
|
|
|
|
|
|
/// }
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 或者完全自定义:
|
|
|
|
|
|
/// protected override void OnHomeClick()
|
|
|
|
|
|
/// {
|
|
|
|
|
|
/// CloseWindow(true);
|
|
|
|
|
|
/// UIManager.Instance.CreateAndOpenWindow("MyCustomMainPanel").Forget();
|
|
|
|
|
|
/// }
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual void OnHomeClick()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 关闭当前窗口
|
|
|
|
|
|
CloseWindow(true);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Default Back Button - 默认返回按钮自动绑定
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 默认返回按钮的节点名配置(子类可重写)
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 默认支持的节点名:
|
|
|
|
|
|
/// - BtnBack: 返回按钮(推荐,最常用)
|
|
|
|
|
|
/// - BackButton: 返回按钮
|
|
|
|
|
|
/// - BtnReturn: 返回按钮
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 自定义示例:
|
|
|
|
|
|
/// protected override string[] DefaultBackButtonNames => new[] { "BtnPrevious" };
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 禁用返回按钮:
|
|
|
|
|
|
/// protected override string[] DefaultBackButtonNames => new string[0];
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual string[] DefaultBackButtonNames => new[] { "BtnBack", "BackButton", "BtnReturn" };
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 绑定所有配置的默认返回按钮
|
|
|
|
|
|
/// 在 DoInit() 阶段自动调用,无需手动调用
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 重要说明:
|
|
|
|
|
|
/// - 返回按钮会调用 Back() 方法,触发 OnBack() 虚方法
|
|
|
|
|
|
/// - 点击返回按钮 = 按下返回键(Android Back / ESC)
|
|
|
|
|
|
/// - 子类通过重写 OnBack() 来自定义返回逻辑
|
|
|
|
|
|
/// - 默认使用 BackStrategy 配置的策略
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void BindDefaultBackButtons()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var buttonName in DefaultBackButtonNames)
|
|
|
|
|
|
{
|
|
|
|
|
|
TryBindBackButton(buttonName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试绑定返回按钮
|
|
|
|
|
|
/// 如果节点不存在,不会报错,只是不绑定
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 绑定后,点击按钮会调用 Back() 方法,触发 OnBack() 虚方法
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void TryBindBackButton(string nodeName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = transform.Find(nodeName);
|
|
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
var btn = trans.GetComponent<Button>();
|
|
|
|
|
|
if (btn)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 绑定到 Back() 方法,会触发 OnBack() 虚方法
|
|
|
|
|
|
BindButton(btn, () => Back().Forget());
|
|
|
|
|
|
DebugUtil.Log("✅ 已自动绑定返回按钮: {0} -> {1} -> Back()", WindowName, nodeName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:返回按钮不需要 OnBackClick() 方法
|
|
|
|
|
|
// 它直接调用 Back() 方法,触发 OnBack() 虚方法
|
|
|
|
|
|
// OnBack() 方法定义在 UIWindow.Lifecycle.cs 中
|
|
|
|
|
|
//
|
|
|
|
|
|
// 自定义返回逻辑示例:
|
|
|
|
|
|
// protected override async UniTask<bool> OnBack()
|
|
|
|
|
|
// {
|
|
|
|
|
|
// SaveCurrentState();
|
|
|
|
|
|
// CloseWindow(false);
|
|
|
|
|
|
// return true; // 返回true表示已处理
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-09-04 14:23:51 +08:00
|
|
|
|
}
|