using DG.Tweening; using Framework; using PhxhSDK; using UnityEngine.UI; public abstract partial class UIWindow { /* ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ UIWindow 生命周期 (Lifecycle) ║ ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ ║ ║ ║ 1. 【Load 阶段】- 资源加载 ║ ║ UIManager.CreateWindow() ║ ║ ├─ 加载预制体资源 ║ ║ ├─ 实例化GameObject ║ ║ └─ 创建UIWindow实例 ║ ║ ║ ║ 2. 【Init 阶段】- 初始化 ║ ║ UIWindow.Init(data) // 窗口初始化(独立调用) ║ ║ ├─ *OnBeforeInit(data) // 预处理数据(不推荐使用) ║ ║ ├─ DoInit() // 基础初始化 ║ ║ │ ├─ AutoBindField() // 绑定UI组件引用 ║ ║ │ ├─ InitScreenAdaption() // 屏幕适配 ║ ║ │ └─ _TryBindBgClose() // 绑定背景关闭按钮 ║ ║ └─ *OnInit() // 初始化UI状态,设置默认值 ║ ║ ║ ║ 3. 【Show 阶段】- 显示 ║ ║ UIWindow.ShowWindow(data) // 显示窗口(公共接口) ║ ║ ├─ *OnBeforeShow(data) // 显示前检查 ║ ║ ├─ DoShow() // 基础显示逻辑 ║ ║ ├─ *OnShow(data) // 显示时业务逻辑处理 ║ ║ ├─ SetActive(true) // 激活GameObject ║ ║ ├─ *OnAfterShow(data) // 显示后处理 ║ ║ └─ 发送UI打开事件 // EventManager.Send ║ ║ ║ ║ 4. 【Update 阶段】- 运行时更新 ║ ║ Update(dt) -> *OnUpdate(dt) // 每帧更新,处理UI逻辑 ║ ║ ║ ║ 5. 【Refresh 阶段】- 数据刷新 ║ ║ Refresh(data) // 数据刷新(公共接口) ║ ║ └─ *OnRefresh(data) // 刷新UI内容,更新显示数据 ║ ║ ║ ║ 6. 【Hide 阶段】- 隐藏 ║ ║ HideWindow() // 隐藏窗口 ║ ║ ├─ *OnHide() // 隐藏回调 ║ ║ ├─ SetActive(false) // 隐藏GameObject ║ ║ └─ 发送UI隐藏事件 // EventManager.Send ║ ║ ║ ║ 7. 【Close 阶段】- 关闭销毁 ║ ║ CloseWindow() -> DestroyWindow() ║ ║ ├─ *OnHide() // 隐藏回调 ║ ║ ├─ *OnRelease() // 释放资源,清理引用 ║ ║ ├─ DoRelease() // 基础资源释放 ║ ║ ├─ Destroy(gameObject) // 销毁GameObject ║ ║ └─ 卸载预制体资源 // AssetManager.Unload ║ ║ ║ ║ 【架构特点】 ║ ║ • 分离式设计: Init和Show独立调用,支持预初始化窗口 ║ ║ • 使用方式: 先调用Init(data)初始化,再调用ShowWindow(data)显示 ║ ║ • 灵活性: 可以先初始化多个窗口,根据需要选择性显示 ║ ║ • 性能优化: 避免显示时的初始化卡顿,提升用户体验 ║ ║ • 数据更新: Show用于显示配置,Refresh用于内容更新,职责分离 ║ ║ ║ ║ 【虚函数重写指南 - 标记为 * 的函数】 ║ ║ ║ ║ 🔸 *OnBeforeInit(data) - 【不推荐】数据预处理 ║ ║ • 时机:在DoInit和OnInit之前调用 ║ ║ • 用途:解析传入数据,设置初始状态 ║ ║ • ⚠️ 不建议使用:建议在OnInit中处理所有初始化逻辑 ║ ║ • 原因:避免逻辑分散,减少维护复杂度 ║ ║ ║ ║ 🔸 *OnInit() - 【常用】UI初始化 ║ ║ • 时机:在DoInit之后,窗口显示之前 ║ ║ • 用途:初始化UI组件,绑定事件,设置默认值 ║ ║ • 示例:按钮绑定,列表初始化,默认文本设置 ║ ║ ║ ║ 🔸 *OnBeforeShow(data) - 【可选】显示前检查 ║ ║ • 时机:在DoShow和OnShow之前调用 ║ ║ • 用途:显示前的条件检查,返回false可取消显示 ║ ║ ║ ║ 🔸 *OnShow(data) - 【常用】显示时业务逻辑 ║ ║ • 时机:窗口显示过程中,在SetActive之前 ║ ║ • 用途:处理显示时的主要业务逻辑,设置显示配置 ║ ║ • 示例:设置窗口模式,初始化显示状态 ║ ║ • 注意:与Refresh职责分离,Show负责显示配置,Refresh负责内容更新 ║ ║ ║ ║ 🔸 *OnAfterShow(data) - 【可选】显示后处理 ║ ║ • 时机:窗口完全显示后,在SetActive之后 ║ ║ • 用途:播放动画,开始计时等后续逻辑 ║ ║ ║ ║ 🔸 *OnUpdate(dt) - 【可选】每帧更新 ║ ║ • 时机:每帧调用(仅在窗口激活时) ║ ║ • 用途:倒计时更新,进度条刷新等 ║ ║ • 注意:避免重度计算,影响性能 ║ ║ ║ ║ 🔸 *OnRefresh(data) - 【推荐】数据刷新 ║ ║ • 时机:调用Refresh(data)时触发 ║ ║ • 用途:更新已显示窗口的内容数据,不重新初始化 ║ ║ • 示例:刷新列表数据,更新文本内容,重新计算显示 ║ ║ • 设计:与Show分离,Show处理显示配置,Refresh处理内容更新 ║ ║ • 调用:只能通过Refresh(data)公共接口调用,不要直接调用OnRefresh ║ ║ ║ ║ 🔸 *OnHide() - 【可选】隐藏时处理 ║ ║ • 时机:窗口隐藏时调用 ║ ║ • 用途:暂停逻辑,保存状态,停止动画 ║ ║ ║ ║ 🔸 *OnRelease() - 【重要】资源释放 ║ ║ • 时机:窗口销毁时调用 ║ ║ • 用途:释放资源,取消订阅,清理引用 ║ ║ • 示例:取消事件监听,释放Tween,清理对象池 ║ ║ ║ ║ 【重要说明】 ║ ║ • 所有虚函数重写时都不需要调用base.OnXxx() ║ ║ • AutoBindField由代码生成工具处理,不要手动重写 ║ ║ • Init和Show分离设计,支持窗口预初始化 ║ ║ • ⚠️ 不建议重写OnBeforeInit,统一在OnInit中处理初始化逻辑 ║ ║ • Show与Refresh职责分离:Show负责显示配置,Refresh负责内容更新 ║ ║ • 禁止直接调用OnXxx虚方法,必须通过对应的公共接口调用 ║ ║ ║ ╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ */ #region Lifecycle Management /// /// 初始化窗口 /// /// 初始化数据 public void Init(object data = null) { try { OnBeforeInit(data); if (isInited) { DebugUtil.LogWarning("window : {0} already inited", WindowName); } else { DoInit(); OnInit(); isInited = true; } } catch (System.Exception e) { DebugUtil.LogError("window : {0} init window error: {1}", WindowName, e.Message); } } /// /// 显示窗口 /// /// 显示数据 public void ShowWindow(object data = null) { // 未被唤醒不执行Show if (IsUnEnabled) { return; } try { if (_isShow) { DebugUtil.LogWarning("window : {0} is show, can't show again", WindowName); } if (!OnBeforeShow(data)) { DebugUtil.LogError("window : {0} on before show return false", WindowName); return; } DoShow(); OnShow(data); if (gameObject == null) { DebugUtil.Log("UI已被销毁:{0}", WindowName); } else { gameObject.SetActive(true); } _isShow = true; OnAfterShow(data); EventManager.Instance.Send(EventManager.EventName.UIOpen, WindowName); } catch (System.Exception e) { DebugUtil.LogError("window : {0} show window error: {1}", WindowName, e.Message); } } /// /// 更新入口 /// public void Update(float dt) { try { _notchScreenAdapter?.UpdateCheck(); OnUpdate(dt); } catch (System.Exception e) { DebugUtil.LogError("window : {0} update window error: {1}", WindowName, e.Message); } } /// /// 刷新窗口数据 /// /// 新数据 public void Refresh(object data) { try { if (isInited) { OnRefresh(data); } else { DebugUtil.LogError("window : {0} not inited", WindowName); } } catch (System.Exception e) { DebugUtil.LogError("window : {0} refresh with data error: {1}", WindowName, e.Message); } } /// /// 隐藏窗口 /// public void HideWindow() { if (!_isShow) { DebugUtil.LogWarning("window : {0} is hide, can't hide again", WindowName); } try { if (UIManager.Instance.WindowInfos.TryGetValue(WindowName, out var windowInfo)) { if (windowInfo.UIOpenType == UIOpenType.FullScreen) { if (!CameraManager.Instance.CheckMainCameraIsActive()) { CameraManager.Instance.SetMainCameraActive(true); } } } OnHide(); gameObject?.SetActive(false); _isShow = false; EventManager.Instance.Send(EventManager.EventName.UIHide, WindowName); } catch (System.Exception e) { DebugUtil.LogError("window : {0} hide window error: {1}", WindowName, e.Message); } } /// /// 关闭窗口 /// /// 关闭类型 public async void CloseWindow(UIWindowCloseType closeType) { try { IsClosing = true; DebugUtil.LogG($"关闭UI:{WindowName}, closeType{closeType}"); if (UIManager.Instance.CheckWindowIsFullScreen(this)) { if (_shutMainCamera) { CameraManager.Instance.SetMainCameraActive(true); } } if (closeType == UIWindowCloseType.HideAndDestroy) { var last = UIManager.Instance.GetLast(); if (last == this) { DebugUtil.LogG($"PopWindow{this.WindowName}"); UIManager.Instance.PopWindow(); } if (UIManager.Instance.UiWindowStack.Count > 0) { if (UIManager.Instance.CheckWindowIsFullScreen(this)) { var window = UIManager.Instance.GetLastFullScreen(); if (window != null && window != this) { if (UIManager.Instance.CheckIsWindowInStack(this)) { UIManager.Instance.ForceRemoveWindow(this); DebugUtil.LogG($"UI出栈,{WindowName}"); } } for (int i = UIManager.Instance.UiWindowStack.Count - 1; i >= 0; i--) { var latestWindow = UIManager.Instance.UiWindowStack[i]; latestWindow.ShowWindow(); if (UIManager.Instance.CheckWindowIsFullScreen(latestWindow)) break; } } else { UIManager.Instance.ForceRemoveWindow(this); } } bool isShowCloseAnim = IsShowOpenAnim; if (isShowCloseAnim) { UIManager.Instance.BlockUIForCloseOperation(); await AnimHide(() => { DestroyWindow(); UIManager.Instance.RemoveWindow(mWindowName); IsClosing = false; }); } else { UIManager.Instance.RemoveWindow(mWindowName); DestroyWindow(); IsClosing = false; } } else if (closeType == UIWindowCloseType.ForceDestroy) { // 强制清除所有界面时使用 DestroyWindow(); UIManager.Instance.RemoveWindow(mWindowName); IsClosing = false; } } catch (System.Exception e) { DebugUtil.LogError("window : {0} close window error: {1}", WindowName, e.Message); } } #endregion #region Internal Implementation /// /// 执行基础初始化 /// private void DoInit() { _isShow = false; _shutMainCamera = UIManager.Instance.IsShutMainCamera(WindowName); IsShowOpenAnim = UIManager.Instance.GetIsAutoPlayAnim(WindowName); AutoBindField(); InitScreenAdaption(); _TryBindBgClose(); } /// /// 执行显示逻辑 /// private void DoShow() { if (UIManager.Instance.WindowInfos.TryGetValue(WindowName, out var windowInfo)) { if (CameraManager.Instance.CheckMainCameraIsActive()) { if (windowInfo.UIOpenType == UIOpenType.FullScreen) { // 特殊处理主界面 if (_shutMainCamera && WindowName != UINameConst.UI_MainPanel) { CameraManager.Instance.SetMainCameraActive(false); } } } } } /// /// 销毁窗口 /// private void DestroyWindow() { DebugUtil.LogG($"DestroyWindow:{WindowName}"); OnHide(); gameObject?.SetActive(false); _isShow = false; EventManager.Instance.Send(EventManager.EventName.UIHide, WindowName); if (gameObject) { if (isInited) { OnRelease(); DoRelease(); isInited = false; } if (UIManager.Instance.UIWindowObjDic.ContainsKey(gameObject)) { UIManager.Instance.UIWindowObjDic.Remove(gameObject); } UnityEngine.Object.Destroy(gameObject); } AssetManager.Instance.Unload(string.Format(UIManager.UI_PREFAB_PATH, mWindowName), true); gameObject = null; } /// /// 基础资源释放 /// private void DoRelease() { EventManager.Instance.Send(EventManager.EventName.UIDestroy, WindowName); UnLoad(); _openAnimSeq?.Kill(); _assetReferenceManager?.Dispose(); _assetReferenceManager = null; _notchScreenAdapter = null; _graphicRaycasterManager = null; } /// /// 绑定背景关闭按钮 /// private void _TryBindBgClose() { var trans = transform.Find("BgClose"); if (trans) { var btn = trans.GetComponent