using Cysharp.Threading.Tasks; using DG.Tweening; using Framework; using PhxhSDK; using UnityEngine.UI; public abstract partial class UIWindow { /* ╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ UIWindow 生命周期 (Lifecycle) ║ ╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣ ║ ║ ║ 【生命周期流程】 ║ ║ 1. Load → UIManager.CreateWindow() 加载预制体 ║ ║ 2. Init → Init() 初始化UI组件 ║ ║ 3. Show → ShowWindow(data) 显示窗口 ║ ║ 4. Update → Update(dt) 显示的界面每帧更新 ║ ║ 5. Refresh → Refresh(data) 刷新数据 ║ ║ 6. Close → CloseWindow(false) 关闭窗口(保留内存) ║ ║ 7. Destroy → CloseWindow(true) 销毁窗口(释放资源) ║ ║ ║ ║ 【核心虚方法】(子类可重写) ║ ║ • OnInit() - 初始化UI组件,绑定事件 ║ ║ • OnBeforeShow() - 显示前验证,返回false取消显示 ║ ║ • OnAfterShow() - 显示后处理,播放动画 ║ ║ • OnUpdate(dt) - 显示的界面每帧更新(避免重度计算) ║ ║ • OnRefresh() - 刷新显示内容 ║ ║ • OnHide() - 隐藏时清理,暂停逻辑 ║ ║ • OnRelease() - 销毁时释放资源(重要:防止内存泄漏) ║ ║ ║ ║ 【注意事项】 ║ ║ ⚠️ 不要重写公共接口方法(Init, ShowWindow, Update等) ║ ║ ⚠️ 不要直接调用OnXxx虚方法,必须通过公共接口 ║ ║ ⚠️ CloseWindow(true)销毁窗口,CloseWindow(false)仅隐藏 ║ ║ ║ ╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ */ #region Lifecycle Management /// /// 初始化窗口 /// public void Init() { try { 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}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace); } } /// /// 显示窗口 /// public void ShowWindow(object data = null) { 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 is null) { DebugUtil.Log("UI已被销毁:{0}", WindowName); } else { gameObject.SetActive(true); } _isShow = true; _isPaused = false; // 新窗口默认是活跃状态(未暂停) OnAfterShow(data); bool isShowOpenAnim = IsShowOpenAnim; if (isShowOpenAnim) { AnimShow(() => { //TODO EventManager.Instance.Send(EventManager.EventName.UIOpen, WindowName); }).Forget(); } else { //OnAfterShow(data); EventManager.Instance.Send(EventManager.EventName.UIOpen, WindowName); } } catch (System.Exception e) { DebugUtil.LogError("window : {0} show window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace); } } /// /// 在显示前截图(如果需要) /// private void CaptureScreenshotIfNeeded() { var config = UIManager.Instance.GetWindowInfo(WindowName); if (config.NeedScreenshot) { var oldActive = gameObject.activeSelf; gameObject.SetActive(false); ScreenshotManager.Instance.CaptureScreenshot(); gameObject.SetActive(oldActive); } } /// /// 自动设置模糊背景(如果需要) /// private void SetupBlurBackgroundIfNeeded() { var config = UIManager.Instance.GetWindowInfo(WindowName); if (!config.NeedScreenshot) return; // 查找约定的 GaussianBlurMask 节点 var blurTransform = transform.Find("GaussianBlurMask"); if (blurTransform != null) { var blurMask = blurTransform.GetComponent(); if (blurMask != null) { blurMask.texture = ScreenshotManager.Instance.GetScreenTexture2D(); blurMask.gameObject.SetActive(true); } } } /// /// 更新入口,界面打开的时候更新 /// public void Update(float dt) { try { _notchScreenAdapter?.UpdateCheck(); OnUpdate(dt); } catch (System.Exception e) { DebugUtil.LogError("window : {0} update window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace); } } /// /// 刷新窗口数据 /// 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}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace); } } /// /// 关闭窗口 /// destroy = false: 关闭但保留内存(快速重开) /// destroy = true: 销毁并释放资源 /// public async void CloseWindow(bool destroy) { try { // 如果窗口已关闭 if (!_isShow) { // 如果不需要销毁,直接返回 if (!destroy) { DebugUtil.LogWarning("window : {0} is already closed", WindowName); return; } // 如果需要销毁,跳过关闭逻辑,直接执行销毁 DebugUtil.LogG($"窗口已关闭,直接销毁UI:{WindowName}"); IsClosing = true; UIManager.Instance.RemoveWindow(mWindowName); DoDestroy(); IsClosing = false; return; } IsClosing = true; // 1. 获取窗口配置 var config = UIManager.Instance.GetWindowInfo(WindowName); // 2. 可见性管理(由 UIWindowVisibilityManager 根据配置决定是否处理) UIWindowVisibilityManager.Instance.HandleVisibilityOnClose(this, config.VisibilityStrategy); // 3. 相机管理(在可见性管理之后处理) UIWindowCameraManager.Instance.HandleCameraOnClose(this); // 4. 隐藏逻辑 OnHide(); gameObject?.SetActive(false); _isShow = false; _isPaused = false; // 重置暂停状态 EventManager.Instance.Send(EventManager.EventName.UIHide, WindowName); // 5. 播放关闭动画 bool isShowCloseAnim = IsShowOpenAnim; if (isShowCloseAnim) { UIManager.Instance.BlockUIForCloseOperation(); await AnimHide(() => { // 动画播放完毕后的回调 if (destroy) { DoDestroy(); UIManager.Instance.RemoveWindow(mWindowName); } IsClosing = false; }); } else { // 7. 如果需要销毁(无动画情况) if (destroy) { DoDestroy(); UIManager.Instance.RemoveWindow(mWindowName); } IsClosing = false; } } catch (System.Exception e) { DebugUtil.LogError("window : {0} close window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace); } } /// /// 暂停窗口 /// /// 功能: /// - 标记窗口为暂停状态 /// - 调用 OnPause 回调 /// - 可选:隐藏渲染(通过 hideRendering 参数控制) /// /// 调用场景: /// - 自动调用:窗口被遮挡时(由 UIWindowVisibilityManager 触发) /// - 手动调用:游戏暂停、广告弹出等特殊场景 /// /// 示例: /// battleUI.PauseWindow(hideRendering: false); // 暂停逻辑但保持显示 /// /// 是否同时隐藏渲染(SetActive(false)) public void PauseWindow(bool hideRendering = true) { // 状态检查 if (!_isShow) { DebugUtil.LogWarning($"[UIWindow] PauseWindow failed: window is not showing ({WindowName})"); return; } if (_isPaused) { DebugUtil.LogWarning($"[UIWindow] PauseWindow ignored: already paused ({WindowName})"); return; } _isPaused = true; // 调用子类的暂停逻辑 OnPause(); // 可选:隐藏渲染 if (hideRendering && gameObject != null && gameObject.activeSelf) { gameObject.SetActive(false); DebugUtil.Log($"[UIWindow] Paused (hidden): {WindowName}"); } else { DebugUtil.Log($"[UIWindow] Paused (logic only): {WindowName}"); } } /// /// 恢复窗口 /// /// 功能: /// - 标记窗口为活跃状态 /// - 调用 OnResume 回调 /// - 可选:显示渲染(通过 showRendering 参数控制) /// /// 调用场景: /// - 自动调用:窗口重新显示时(由 UIWindowVisibilityManager 触发) /// - 手动调用:游戏恢复、广告关闭等特殊场景 /// /// 示例: /// battleUI.ResumeWindow(showRendering: true); // 恢复逻辑并显示 /// /// 是否同时显示渲染(SetActive(true)) public void ResumeWindow(bool showRendering = true) { // 状态检查 if (!_isShow) { DebugUtil.LogWarning($"[UIWindow] ResumeWindow failed: window is not showing ({WindowName})"); return; } if (!_isPaused) { DebugUtil.LogWarning($"[UIWindow] ResumeWindow ignored: not paused ({WindowName})"); return; } _isPaused = false; // 可选:显示渲染 if (showRendering && gameObject != null && !gameObject.activeSelf) { gameObject.SetActive(true); DebugUtil.Log($"[UIWindow] Resumed (shown): {WindowName}"); } else { DebugUtil.Log($"[UIWindow] Resumed (logic only): {WindowName}"); } // 调用子类的恢复逻辑 OnResume(); } #endregion #region User Interaction #endregion #region Internal Implementation /// /// 恢复主相机状态(已废弃,由 UIWindowCameraManager 统一管理) /// [System.Obsolete("RestoreMainCamera已废弃,相机状态由 UIWindowCameraManager 统一管理")] private void RestoreMainCamera() { // 相机管理逻辑已移至 UIWindowCameraManager.HandleCameraOnClose // 保留此方法以防止破坏性更改 } /// /// 执行基础初始化 /// private void DoInit() { _isShow = false; var metaInfo = UIManager.Instance.GetWindowInfo(WindowName); IsShowOpenAnim = metaInfo.IsAutoAnim; BackStrategy = UIBackStrategyFactory.CreateStrategy(metaInfo.BackStrategyType); AutoBindField(); InitScreenAdaption(); BindDefaultCloseButtons(); BindDefaultHomeButtons(); BindDefaultBackButtons(); } /// /// 执行显示逻辑 /// private void DoShow() { // 🎯 在显示前截图(如果需要) CaptureScreenshotIfNeeded(); // 🎯 自动设置模糊背景(如果需要) SetupBlurBackgroundIfNeeded(); // 🎯 相机管理(在窗口显示后处理) var config = UIManager.Instance.GetWindowInfo(WindowName); UIWindowVisibilityManager.Instance.HandleVisibilityOnOpen(this, config.VisibilityStrategy); UIWindowCameraManager.Instance.HandleCameraOnOpen(this); } /// /// 执行销毁逻辑 /// private void DoDestroy() { DebugUtil.LogG($"DoDestroy:{WindowName}"); // 如果窗口还在显示状态,先调用 OnHide if (_isShow) { OnHide(); _isShow = false; } // 确保 GameObject 隐藏 if (gameObject != null) { gameObject.SetActive(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; } #endregion #region Virtual Methods // Init Phase /// /// UI初始化 /// protected virtual void OnInit(){} /// /// 自动绑定字段 /// protected virtual void AutoBindField(){} // Show Phase /// /// 显示前检查(返回false可取消显示) /// protected virtual bool OnBeforeShow(object data) { return true; } /// /// 显示时处理(已废弃,建议使用OnAfterShow) /// [System.Obsolete("OnShow已废弃,请使用OnAfterShow方法替代。OnAfterShow在窗口完全显示后调用,提供更稳定的显示时机。")] protected virtual void OnShow(object data){} /// /// 显示后处理 /// protected virtual void OnAfterShow(object data){} /// /// IsShow的界面每帧更新 /// protected virtual void OnUpdate(float dt){} // Refresh Phase /// /// 数据刷新 /// protected virtual void OnRefresh(object data) {} // Hide Phase /// /// 隐藏时处理 /// protected virtual void OnHide(){} // Pause/Resume Phase /// /// 窗口暂停回调(子类重写) /// /// 调用时机: /// - 自动调用:窗口被遮挡时(UIWindowVisibilityManager 触发) /// - 手动调用:调用 PauseWindow() 时 /// /// 建议处理: /// - 停止播放背景音乐/音效 /// - 暂停动画/粒子特效 /// - 暂停定时器/倒计时 /// - 暂停网络轮询(可选) /// /// 示例: /// /// protected override void OnPause() /// { /// if (_bgmHandle != -1) /// AudioManager.Instance.PauseBGM(_bgmHandle); /// } /// /// protected virtual void OnPause() { } /// /// 窗口恢复回调(子类重写) /// /// 调用时机: /// - 自动调用:窗口重新显示时(UIWindowVisibilityManager 触发) /// - 手动调用:调用 ResumeWindow() 时 /// /// 建议处理: /// - 恢复播放背景音乐/音效 /// - 恢复动画/粒子特效 /// - 恢复定时器/倒计时 /// - 刷新数据(可选) /// /// 示例: /// /// protected override void OnResume() /// { /// if (_bgmHandle != -1) /// AudioManager.Instance.ResumeBGM(_bgmHandle); /// } /// /// protected virtual void OnResume() { } // Release Phase /// /// 资源释放 /// protected virtual void OnRelease(){} #endregion }