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