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(data) 初始化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(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}\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; 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; 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); } } #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 /// /// 初始化前预处理(已废弃,建议使用OnInit) /// [System.Obsolete("OnBeforeInit已废弃,请使用OnInit方法替代。OnInit提供更清晰的初始化流程和更好的代码组织。")] protected virtual void OnBeforeInit(object data = null){} /// /// 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){} /// /// 每帧更新 /// protected virtual void OnUpdate(float dt){} // Refresh Phase /// /// 数据刷新 /// protected virtual void OnRefresh(object data) {} // Hide Phase /// /// 隐藏时处理 /// protected virtual void OnHide(){} // Release Phase /// /// 资源释放 /// protected virtual void OnRelease(){} #endregion }