using System; using Cysharp.Threading.Tasks; using Framework; using PhxhSDK; using UnityEngine; using UnityEngine.UI; /* ╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ UIWindow 按钮绑定模块 (Button Binding) ║ ╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ ║ ║ ║ 【模块功能】 ║ ║ 本模块提供了两大核心功能: ║ ║ 1. 手动按钮绑定 API - 在OnInit()中手动绑定自定义按钮 ║ ║ 2. 默认按钮自动绑定 - 约定节点名自动绑定常用按钮(返回按钮) ║ ║ ║ ║ 注意:默认关闭按钮和回主界面按钮的处理已移至独立的 partial 文件: ║ ║ • UIWindow.DefaultCloseButton.cs - 处理默认关闭按钮(BgClose、BtnClose) ║ ║ • UIWindow.DefaultHomeButton.cs - 处理默认回主界面按钮(BtnHome、BtnBackHome、HomeButton) ║ ║ ║ ║ 【使用方式】 ║ ║ ║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ │ 方式一:使用默认按钮(推荐) │ ║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ ║ ║ 只需在预制体中创建约定名称的按钮节点,框架会自动绑定: ║ ║ ║ ║ ⬅️ 返回按钮: ║ ║ 节点名: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 async UniTask OnBack() ║ ║ { ║ ║ SaveCurrentState(); ║ ║ CloseWindow(false); ║ ║ return true; ║ ║ } ║ ║ } ║ ║ ║ ║ 【更多信息】 ║ ║ • 关闭按钮详细文档:Assets/Code/Scripts/Framework/UI/UIWindow.DefaultCloseButton.cs ║ ║ • 回主界面按钮详细文档:Assets/Code/Scripts/Framework/UI/UIWindow.DefaultHomeButton.cs ║ ║ • 返回按钮详细文档:本文件中的 Default Back Button 部分 ║ ║ ║ ╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ */ /// /// UI窗口基类 - 按钮绑定部分 /// 提供按钮绑定API和默认按钮自动绑定功能 /// public abstract partial class UIWindow { #region Button Binding Core - 按钮绑定核心逻辑 /// /// 处理按钮点击的音频逻辑 /// private void HandleButtonAudio(Button button, bool playAudio) { if (!playAudio) return; var clickAudio = button.GetComponent(); if (clickAudio) { if (clickAudio.IsPlayAudio && !string.IsNullOrEmpty(clickAudio.AudioKey)) { AudioManager.Instance.PlayAudio(clickAudio.AudioKey); } } else { CommonUtilsFramework.PlayUICommonSound(); } } /// /// 绑定按钮点击事件的核心逻辑(无参数) /// private void BindButtonCore(Button button, Action action, bool playAudio = true) { if (button is null) { DebugUtil.LogError("传入按钮为空,无法绑定点击事件!"); return; } button.onClick.RemoveAllListeners(); button.onClick.AddListener(() => { DebugUtil.Log("按钮被点击: {0}", button.gameObject.name); if (UIManager.IsUIInputBlocked) return; UIManager.Instance.BlockUIForNormalOperation(); HandleButtonAudio(button, playAudio); action?.Invoke(); }); DebugUtil.Log("按钮绑定完成: {0}", button.gameObject.name); } /// /// 绑定按钮点击事件的核心逻辑(带参数) /// private void BindButtonCore(Button button, Action action, T parameter, bool playAudio = true) { if (button is null) return; button.onClick.RemoveAllListeners(); button.onClick.AddListener(() => { if (UIManager.IsUIInputBlocked) return; UIManager.Instance.BlockUIForNormalOperation(); HandleButtonAudio(button, playAudio); if (parameter == null) { DebugUtil.LogError("=== 传入参数为空! ==="); } action?.Invoke(parameter); }); } #endregion #region Button Binding Public API - 手动绑定按钮的公共API /// /// 通过路径绑定按钮 /// /// 按钮节点路径(相对于窗口根节点) /// 点击回调 /// 是否播放点击音效(默认true) /// Button组件 /// /// BindButton("TopBar/BtnSettings", OnSettingsClick); /// public Button BindButton(string target, Action action, bool playAudio = true) { GameObject obj = transform.Find(target)?.gameObject; if (obj is not null) { Button button = obj.GetComponent