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

668 lines
46 KiB
C#
Raw Normal View History

2025-09-22 17:45:42 +08:00
using Cysharp.Threading.Tasks;
using DG.Tweening;
using Framework;
using PhxhSDK;
using UnityEngine.UI;
public abstract partial class UIWindow
{
2025-09-10 16:05:21 +08:00
/*
UIWindow (Lifecycle)
1. Load -
UIManager.CreateWindow()
2025-09-10 16:05:21 +08:00
GameObject
UIWindow
2. Init -
2025-09-13 14:12:31 +08:00
UIWindow.Init(data) // 窗口初始化(公共接口,不可重写) ║
2025-09-10 16:05:21 +08:00
DoInit() // 基础初始化 ║
2025-09-13 14:12:31 +08:00
*AutoBindField() // 绑定UI组件引用 ║
2025-09-10 16:05:21 +08:00
InitScreenAdaption() // 屏幕适配 ║
_TryBindBgClose() // 绑定背景关闭按钮 ║
2025-09-10 16:05:21 +08:00
*OnInit() // 初始化UI状态设置默认值 ║
3. Show -
2025-09-13 14:12:31 +08:00
UIWindow.ShowWindow(data) // 显示窗口(公共接口,不可重写) ║
*OnBeforeShow(data) // 显示前检查 ║
DoShow() // 基础显示逻辑 ║
2025-09-11 16:51:41 +08:00
SetActive(true) // 激活GameObject ║
*OnAfterShow(data) // 显示后处理 ║
2025-09-11 16:51:41 +08:00
UI // EventManager.Send ║
2025-09-10 16:05:21 +08:00
4. Update -
2025-09-13 14:12:31 +08:00
UIWindow.Update(dt) // 更新入口(公共接口,不可重写) ║
*OnUpdate(dt) // 每帧更新处理UI逻辑 ║
2025-09-10 16:05:21 +08:00
5. Refresh -
2025-09-13 14:12:31 +08:00
UIWindow.Refresh(data) // 数据刷新(公共接口,不可重写) ║
*OnRefresh(data) // 刷新UI内容更新显示数据 ║
2025-09-10 16:05:21 +08:00
2025-12-26 12:16:37 +08:00
6. Interaction -
UIWindow.Back(data) // 处理返回键(公共接口,不可重写) ║
*OnBack(data) // 返回键处理逻辑(虚方法,可重写) ║
BackStrategy.HandleBack() // 默认使用策略模式 ║
None:
CloseSelf:
DoNothing:
ShowExitConfirm: 退
7. Close -
UIWindow.CloseWindow(destroy) // 关闭窗口(公共接口,不可重写) ║
*OnHide() // 关闭回调 ║
2025-09-10 16:05:21 +08:00
SetActive(false) // 隐藏GameObject ║
UI // EventManager.Send ║
2025-09-10 16:05:21 +08:00
2025-12-26 12:16:37 +08:00
8. Destroy -
UIWindow.CloseWindow(true) // 关闭并销毁窗口 ║
DoDestroy() // 内部销毁逻辑 ║
2025-12-26 12:16:37 +08:00
*OnHide() // 关闭回调(如果还未调用) ║
2025-09-13 14:12:31 +08:00
*OnRelease() // 释放资源,清理引用 ║
DoRelease() // 基础资源释放 ║
Destroy(gameObject) // 销毁GameObject ║
// AssetManager.Unload ║
🔒 :
🎯 : InitShowShowRefresh
:
🛡 :
📋 : 使
使
: UIManager.CreateWindow() Init(data) ShowWindow(data)
: Refresh(data)
2025-12-26 12:16:37 +08:00
: ESC/ Back() OnBack() BackStrategy
: CloseWindow(false) / ShowWindow()
: CloseWindow(destroy: true)
2025-09-13 14:12:31 +08:00
- *
🔸 *OnBeforeInit(data) -
DoInitOnInit
使OnInit
OnInit()
🔸 *OnInit() - UI
DoInit
UI
GameObject访UI
🔸 *AutoBindField() -
DoInit
UI
🔸 *OnBeforeShow(data) -
DoShowOnShow
false
使
2025-09-24 20:46:04 +08:00
🔸 *OnShow(data) -
2025-09-13 14:12:31 +08:00
SetActive
2025-12-26 12:16:37 +08:00
使OnAfterShow
2025-09-11 16:51:41 +08:00
2025-12-26 12:16:37 +08:00
🔸 *OnAfterShow(data) -
2025-09-13 14:12:31 +08:00
SetActive
🔸 *OnUpdate(dt) -
使
🔸 *OnRefresh(data) -
Refresh(data)
Show
Refresh(data)
2025-12-26 12:16:37 +08:00
🔸 *OnBack(data) -
AndroidESCBack()
truefalse
BackStrategyNone/CloseSelf/DoNothing/ShowExitConfirm
base.OnBack()使
Back()
2025-09-13 14:12:31 +08:00
🔸 *OnHide() -
2025-09-10 16:05:21 +08:00
🔸 *OnRelease() -
2025-09-13 14:12:31 +08:00
OnHide
Tween
🚫
2025-12-26 12:16:37 +08:00
Init, ShowWindow, Update, Refresh, Back, CloseWindow
2025-09-13 14:12:31 +08:00
OnXxx
2025-12-26 12:16:37 +08:00
OnXxxbase.OnXxx()
2025-09-13 14:12:31 +08:00
OnInit使OnBeforeInit
ShowRefresh
OnRelease
使OnUpdate
2025-12-26 12:16:37 +08:00
Init(data), ShowWindow(data), Refresh(data), Back(data)
BackStrategyOnBack
OnBackbase.OnBack()
2025-09-13 14:12:31 +08:00
💡
"模板方法模式"
2025-09-10 16:05:21 +08:00
*/
2025-09-12 15:18:50 +08:00
#region Lifecycle Management
2025-09-10 21:02:34 +08:00
/// <summary>
/// 初始化窗口
/// </summary>
2025-09-12 15:18:50 +08:00
/// <param name="data">初始化数据</param>
2025-09-10 16:05:21 +08:00
public void Init(object data = null)
{
try
{
OnBeforeInit(data);
if (isInited)
{
DebugUtil.LogWarning("window : {0} already inited", WindowName);
}
else
{
DoInit();
OnInit();
isInited = true;
}
2025-09-10 16:05:21 +08:00
}
catch (System.Exception e)
2025-09-10 16:05:21 +08:00
{
2025-11-04 16:08:13 +08:00
DebugUtil.LogError("window : {0} init window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
}
2025-09-10 16:05:21 +08:00
}
2025-09-12 15:18:50 +08:00
/// <summary>
/// 显示窗口
/// </summary>
/// <param name="data">显示数据</param>
public void ShowWindow(object data = null)
{
try
{
if (_isShow)
{
DebugUtil.LogWarning("window : {0} is show, can't show again", WindowName);
}
2025-12-25 15:01:35 +08:00
// 🎯 在显示前截图(如果需要)
CaptureScreenshotIfNeeded();
// 🎯 自动设置模糊背景(如果需要)
SetupBlurBackgroundIfNeeded();
2025-09-12 15:18:50 +08:00
if (!OnBeforeShow(data))
{
DebugUtil.LogError("window : {0} on before show return false", WindowName);
return;
}
DoShow();
OnShow(data);
if (gameObject is null)
2025-09-12 15:18:50 +08:00
{
DebugUtil.Log("UI已被销毁:{0}", WindowName);
}
else
{
gameObject.SetActive(true);
}
_isShow = true;
2025-12-25 20:33:19 +08:00
OnAfterShow(data);
2025-09-22 17:45:42 +08:00
bool isShowOpenAnim = IsShowOpenAnim;
if (isShowOpenAnim)
{
2025-12-25 20:33:19 +08:00
2025-09-22 17:45:42 +08:00
AnimShow(() =>
{
2025-12-25 20:33:19 +08:00
//TODO
2025-09-22 17:45:42 +08:00
EventManager.Instance.Send(EventManager.EventName.UIOpen, WindowName);
}).Forget();
}
else
{
2025-12-25 20:33:19 +08:00
//OnAfterShow(data);
2025-09-22 17:45:42 +08:00
EventManager.Instance.Send(EventManager.EventName.UIOpen, WindowName);
}
2025-09-12 15:18:50 +08:00
}
catch (System.Exception e)
{
2025-11-04 16:08:13 +08:00
DebugUtil.LogError("window : {0} show window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
2025-09-12 15:18:50 +08:00
}
}
2025-12-25 15:01:35 +08:00
/// <summary>
/// 在显示前截图(如果窗口配置需要截图)
/// </summary>
private void CaptureScreenshotIfNeeded()
{
var config = UIManager.Instance.GetWindowInfo(WindowName);
if (config.NeedScreenshot)
{
ScreenshotManager.Instance.CaptureScreenshot();
}
}
/// <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);
}
}
}
2025-09-10 21:02:34 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 更新入口
2025-09-10 21:02:34 +08:00
/// </summary>
2025-09-12 15:18:50 +08:00
public void Update(float dt)
2025-09-10 16:05:21 +08:00
{
try
{
_notchScreenAdapter?.UpdateCheck();
OnUpdate(dt);
}
catch (System.Exception e)
{
2025-11-04 16:08:13 +08:00
DebugUtil.LogError("window : {0} update window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
}
}
2025-09-12 15:18:50 +08:00
2025-09-10 21:02:34 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 刷新窗口数据
2025-09-10 21:02:34 +08:00
/// </summary>
2025-09-12 15:18:50 +08:00
/// <param name="data">新数据</param>
public void Refresh(object data)
2025-09-10 21:02:34 +08:00
{
try
2025-09-10 21:02:34 +08:00
{
if (isInited)
{
OnRefresh(data);
}
else
{
DebugUtil.LogError("window : {0} not inited", WindowName);
}
2025-09-10 21:02:34 +08:00
}
catch (System.Exception e)
2025-09-10 21:02:34 +08:00
{
2025-11-04 16:08:13 +08:00
DebugUtil.LogError("window : {0} refresh with data error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
2025-09-10 21:02:34 +08:00
}
}
2025-09-12 15:18:50 +08:00
/// <summary>
/// 关闭窗口
///
/// 参数说明:
/// - destroy = false: 关闭但保留在内存中(快速重开,如背包、角色面板)
/// - destroy = true: 关闭并销毁,释放资源(不再需要的窗口)
///
/// 行为:
/// 1. 恢复主相机状态
/// 2. 处理导航栈移除(由栈管理器根据配置决定)
/// 3. 恢复下层窗口可见性(由可见性管理器根据配置决定)
/// 4. 调用 OnHide() 生命周期
/// 5. 隐藏窗口渲染GameObject.SetActive(false)
/// 6. 修改逻辑状态_isShow = false
/// 7. 发送 UIHide 事件
/// 8. 播放关闭动画(如果配置了)
/// 9. 如果 destroy = true销毁 GameObject 并释放资源
///
/// 注意:
/// - 如果窗口已关闭_isShow = false且 destroy = false跳过
/// - 如果窗口已关闭_isShow = false且 destroy = true跳过关闭逻辑但仍执行销毁
2025-09-12 15:18:50 +08:00
/// </summary>
/// <param name="destroy">是否销毁窗口</param>
public async void CloseWindow(bool destroy)
2025-09-12 15:18:50 +08:00
{
try
{
// 如果窗口已关闭
if (!_isShow)
2025-09-12 15:18:50 +08:00
{
// 如果不需要销毁,直接返回
if (!destroy)
2025-09-12 15:18:50 +08:00
{
DebugUtil.LogWarning("window : {0} is already closed", WindowName);
return;
2025-09-12 15:18:50 +08:00
}
// 如果需要销毁,跳过关闭逻辑,直接执行销毁
DebugUtil.LogG($"窗口已关闭直接销毁UI:{WindowName}");
IsClosing = true;
UIManager.Instance.RemoveWindow(mWindowName);
DoDestroy();
IsClosing = false;
return;
2025-09-12 15:18:50 +08:00
}
IsClosing = true;
// 1. 恢复主相机
RestoreMainCamera();
// 2. 获取窗口配置
var config = UIManager.Instance.GetWindowInfo(WindowName);
2025-12-25 20:26:05 +08:00
// 3. 可见性管理(由 UIWindowVisibilityManager 根据配置决定是否处理)
UIWindowVisibilityManager.Instance.HandleVisibilityOnClose(this, config.VisibilityStrategy);
2025-12-25 20:26:05 +08:00
// 4. 隐藏逻辑
2025-09-12 15:18:50 +08:00
OnHide();
gameObject?.SetActive(false);
_isShow = false;
EventManager.Instance.Send(EventManager.EventName.UIHide, WindowName);
2025-12-25 20:26:05 +08:00
// 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)
{
2025-11-04 16:08:13 +08:00
DebugUtil.LogError("window : {0} close window error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
}
}
2025-09-10 21:02:34 +08:00
#endregion
2025-12-26 12:16:37 +08:00
#region User Interaction
/// <summary>
/// 处理返回键(公共接口,不可重写)
/// 框架会按照从上到下的顺序调用所有可见窗口的Back()方法,
/// 直到某个窗口处理并返回true为止
/// </summary>
/// <returns>是否成功处理返回键true表示已处理false表示未处理继续向下传递</returns>
public async UniTask<bool> Back()
{
try
{
return await OnBack();
}
catch (System.Exception e)
{
DebugUtil.LogError("window : {0} back error: {1}\n===Stack===\n{2}\n======", WindowName, e.Message, e.StackTrace);
return false;
}
}
/// <summary>
/// 返回键处理(虚方法,子类可重写)
/// 默认通过返回策略模式处理
/// </summary>
/// <returns>是否成功处理返回键true表示已处理false表示未处理继续向下传递</returns>
protected virtual async UniTask<bool> OnBack()
{
if (!GraphicRaycasterManager.IsEnableGraphicRaycaster)
return true;
// 使用策略模式处理返回键
if (BackStrategy != null)
{
return await BackStrategy.HandleBack(this);
}
return false;
}
#endregion
2025-09-12 15:18:50 +08:00
#region Internal Implementation
/// <summary>
/// 恢复主相机状态
/// </summary>
private void RestoreMainCamera()
{
var config = UIManager.Instance.GetWindowInfo(WindowName);
2025-12-24 14:40:00 +08:00
if (config.VisibilityStrategy == UIVisibilityStrategy.Occlusion && _shutMainCamera)
{
if (!CameraManager.Instance.CheckMainCameraIsActive())
{
CameraManager.Instance.SetMainCameraActive(true);
}
}
}
2025-09-12 15:18:50 +08:00
/// <summary>
/// 执行基础初始化
/// </summary>
private void DoInit()
{
_isShow = false;
2025-12-26 17:02:41 +08:00
var metaInfo = UIManager.Instance.GetWindowInfo(WindowName);
_shutMainCamera = metaInfo.ShutMainCamera;
IsShowOpenAnim = metaInfo.IsAutoAnim;
BackStrategy = UIBackStrategyFactory.CreateStrategy(metaInfo.BackStrategyType);
2025-09-12 15:18:50 +08:00
AutoBindField();
InitScreenAdaption();
BindDefaultCloseButtons();
BindDefaultHomeButtons();
BindDefaultBackButtons();
2025-09-12 15:18:50 +08:00
}
2025-09-10 21:02:34 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 执行显示逻辑
/// </summary>
2025-09-10 19:54:45 +08:00
private void DoShow()
{
if (UIManager.Instance.WindowInfos.TryGetValue(WindowName, out var windowInfo))
{
if (CameraManager.Instance.CheckMainCameraIsActive())
{
2025-12-24 14:40:00 +08:00
if (windowInfo.VisibilityStrategy == UIVisibilityStrategy.Occlusion)
{
2025-09-12 15:18:50 +08:00
// 特殊处理主界面
if (_shutMainCamera)
{
CameraManager.Instance.SetMainCameraActive(false);
}
}
}
}
}
/// <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)
{
2025-09-09 20:26:41 +08:00
if (isInited)
{
OnRelease();
2025-09-12 15:18:50 +08:00
DoRelease();
2025-09-09 20:26:41 +08:00
isInited = false;
}
2025-09-12 15:18:50 +08:00
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;
}
2025-09-10 19:54:45 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 基础资源释放
/// </summary>
2025-09-12 15:18:50 +08:00
private void DoRelease()
{
2025-09-12 15:18:50 +08:00
EventManager.Instance.Send(EventManager.EventName.UIDestroy, WindowName);
2025-09-12 10:54:10 +08:00
2025-09-12 15:18:50 +08:00
UnLoad();
_openAnimSeq?.Kill();
_assetReferenceManager?.Dispose();
_assetReferenceManager = null;
_notchScreenAdapter = null;
_graphicRaycasterManager = null;
}
#endregion
2025-09-12 15:18:50 +08:00
#region Virtual Methods
2025-09-12 15:18:50 +08:00
// Init Phase
/// <summary>
/// 初始化前预处理不推荐使用建议在OnInit中处理
/// </summary>
2025-09-24 20:46:04 +08:00
[System.Obsolete("OnBeforeInit已废弃请使用OnInit方法替代。OnInit提供更清晰的初始化流程和更好的代码组织。")]
protected virtual void OnBeforeInit(object data = null){}
/// <summary>
2025-09-12 15:18:50 +08:00
/// UI初始化
/// </summary>
protected virtual void OnInit(){}
2025-09-12 15:18:50 +08:00
/// <summary>
/// 自动绑定字段
/// </summary>
protected virtual void AutoBindField(){}
2025-09-11 16:51:41 +08:00
2025-09-12 15:18:50 +08:00
// Show Phase
/// <summary>
/// 显示前检查
/// </summary>
2025-09-12 10:54:10 +08:00
protected virtual bool OnBeforeShow(object data)
{
return true;
}
2025-09-11 16:39:35 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 显示时处理
2025-09-11 16:39:35 +08:00
/// </summary>
2025-09-24 20:46:04 +08:00
[System.Obsolete("OnShow已废弃请使用OnAfterShow方法替代。OnAfterShow在窗口完全显示后调用提供更稳定的显示时机。")]
protected virtual void OnShow(object data){}
/// <summary>
2025-09-12 15:18:50 +08:00
/// 显示后处理
/// </summary>
protected virtual void OnAfterShow(object data){}
2025-09-12 15:18:50 +08:00
/// <summary>
2025-09-12 15:18:50 +08:00
/// 每帧更新
/// </summary>
protected virtual void OnUpdate(float dt){}
2025-09-12 15:18:50 +08:00
// Refresh Phase
/// <summary>
2025-09-12 15:18:50 +08:00
/// 数据刷新
/// </summary>
protected virtual void OnRefresh(object data) {}
2025-09-12 15:18:50 +08:00
// Hide Phase
/// <summary>
2025-09-12 15:18:50 +08:00
/// 隐藏时处理
/// </summary>
protected virtual void OnHide(){}
2025-09-12 15:18:50 +08:00
// Release Phase
/// <summary>
2025-09-12 15:18:50 +08:00
/// 资源释放
/// </summary>
protected virtual void OnRelease(){}
2025-09-12 15:18:50 +08:00
#endregion
}