NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/UI/UIWindow.Lifecycle.cs

462 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
/// <summary>
/// 初始化窗口
/// </summary>
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);
}
}
/// <summary>
/// 显示窗口
/// </summary>
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);
}
}
/// <summary>
/// 在显示前截图(如果需要)
/// </summary>
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);
}
}
/// <summary>
/// 自动设置模糊背景(如果需要)
/// </summary>
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<UnityEngine.UI.RawImage>();
if (blurMask != null)
{
blurMask.texture = ScreenshotManager.Instance.GetScreenTexture2D();
blurMask.gameObject.SetActive(true);
}
}
}
/// <summary>
/// 更新入口,界面打开的时候更新
/// </summary>
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);
}
}
/// <summary>
/// 刷新窗口数据
/// </summary>
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);
}
}
/// <summary>
/// 关闭窗口
/// destroy = false: 关闭但保留内存(快速重开)
/// destroy = true: 销毁并释放资源
/// </summary>
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
/// <summary>
/// 恢复主相机状态(已废弃,由 UIWindowCameraManager 统一管理)
/// </summary>
[System.Obsolete("RestoreMainCamera已废弃相机状态由 UIWindowCameraManager 统一管理")]
private void RestoreMainCamera()
{
// 相机管理逻辑已移至 UIWindowCameraManager.HandleCameraOnClose
// 保留此方法以防止破坏性更改
}
/// <summary>
/// 执行基础初始化
/// </summary>
private void DoInit()
{
_isShow = false;
var metaInfo = UIManager.Instance.GetWindowInfo(WindowName);
IsShowOpenAnim = metaInfo.IsAutoAnim;
BackStrategy = UIBackStrategyFactory.CreateStrategy(metaInfo.BackStrategyType);
AutoBindField();
InitScreenAdaption();
BindDefaultCloseButtons();
BindDefaultHomeButtons();
BindDefaultBackButtons();
}
/// <summary>
/// 执行显示逻辑
/// </summary>
private void DoShow()
{
// 🎯 在显示前截图(如果需要)
CaptureScreenshotIfNeeded();
// 🎯 自动设置模糊背景(如果需要)
SetupBlurBackgroundIfNeeded();
// 🎯 相机管理(在窗口显示后处理)
var config = UIManager.Instance.GetWindowInfo(WindowName);
UIWindowVisibilityManager.Instance.HandleVisibilityOnOpen(this, config.VisibilityStrategy);
UIWindowCameraManager.Instance.HandleCameraOnOpen(this);
}
/// <summary>
/// 执行销毁逻辑
/// </summary>
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;
}
/// <summary>
/// 基础资源释放
/// </summary>
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
/// <summary>
/// 初始化前预处理已废弃建议使用OnInit
/// </summary>
[System.Obsolete("OnBeforeInit已废弃请使用OnInit方法替代。OnInit提供更清晰的初始化流程和更好的代码组织。")]
protected virtual void OnBeforeInit(object data = null){}
/// <summary>
/// UI初始化
/// </summary>
protected virtual void OnInit(){}
/// <summary>
/// 自动绑定字段
/// </summary>
protected virtual void AutoBindField(){}
// Show Phase
/// <summary>
/// 显示前检查返回false可取消显示
/// </summary>
protected virtual bool OnBeforeShow(object data)
{
return true;
}
/// <summary>
/// 显示时处理已废弃建议使用OnAfterShow
/// </summary>
[System.Obsolete("OnShow已废弃请使用OnAfterShow方法替代。OnAfterShow在窗口完全显示后调用提供更稳定的显示时机。")]
protected virtual void OnShow(object data){}
/// <summary>
/// 显示后处理
/// </summary>
protected virtual void OnAfterShow(object data){}
/// <summary>
/// 每帧更新
/// </summary>
protected virtual void OnUpdate(float dt){}
// Refresh Phase
/// <summary>
/// 数据刷新
/// </summary>
protected virtual void OnRefresh(object data) {}
// Hide Phase
/// <summary>
/// 隐藏时处理
/// </summary>
protected virtual void OnHide(){}
// Release Phase
/// <summary>
/// 资源释放
/// </summary>
protected virtual void OnRelease(){}
#endregion
}