2025-09-04 12:16:08 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
|
|
using DG.Tweening;
|
|
|
|
|
|
using Framework;
|
|
|
|
|
|
using PhxhSDK;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// UI窗口基类 - 生命周期管理部分
|
2025-09-12 15:18:50 +08:00
|
|
|
|
///
|
|
|
|
|
|
/// 功能概述:
|
|
|
|
|
|
/// - 窗口生命周期管理(Init → Show → Update → Hide → Close)
|
|
|
|
|
|
/// - 资源加载与释放管理
|
|
|
|
|
|
/// - 屏幕适配与相机控制
|
|
|
|
|
|
/// - 动画播放与UI事件处理
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 设计特点:
|
|
|
|
|
|
/// - Init和Show分离设计,支持窗口预初始化
|
|
|
|
|
|
/// - 完整的生命周期钩子函数,便于子类扩展
|
|
|
|
|
|
/// - 异常安全的显示/隐藏逻辑
|
|
|
|
|
|
/// - 自动资源管理和内存清理
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract partial class UIWindow
|
|
|
|
|
|
{
|
2025-09-10 16:05:21 +08:00
|
|
|
|
/*
|
|
|
|
|
|
╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
|
|
|
|
|
║ UIWindow 生命周期 (Lifecycle) ║
|
|
|
|
|
|
╠══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 1. 【Load 阶段】- 资源加载 ║
|
|
|
|
|
|
║ UIRoot.CreateWindow() ║
|
|
|
|
|
|
║ ├─ 加载预制体资源 ║
|
|
|
|
|
|
║ ├─ 实例化GameObject ║
|
|
|
|
|
|
║ └─ 创建UIWindow实例 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 2. 【Init 阶段】- 初始化 ║
|
|
|
|
|
|
║ UIWindow.Init(data) // 窗口初始化(独立调用) ║
|
|
|
|
|
|
║ ├─ *OnBeforeInit(data) // 预处理数据 (原 PreLoad) ║
|
|
|
|
|
|
║ ├─ DoInit() // 基础初始化 ║
|
|
|
|
|
|
║ │ ├─ AutoBindField() // 绑定UI组件引用 ║
|
|
|
|
|
|
║ │ ├─ InitScreenAdaption() // 屏幕适配 ║
|
|
|
|
|
|
║ │ └─ _TryBindBgClose() // 绑定通用事件 ║
|
|
|
|
|
|
║ └─ *OnInit() // 初始化UI状态,设置默认值 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 3. 【Show 阶段】- 显示 ║
|
|
|
|
|
|
║ UIWindow.ShowWindow(data) // 显示窗口(公共接口) ║
|
2025-09-11 16:51:41 +08:00
|
|
|
|
║ ├─ DoShow() // 处理相机状态等显示逻辑 ║
|
|
|
|
|
|
║ ├─ *OnShow(data) // 显示时回调,业务逻辑处理 ║
|
|
|
|
|
|
║ ├─ SetActive(true) // 激活GameObject ║
|
|
|
|
|
|
║ ├─ *OnAfterShow(data) // 显示后回调,最终处理 ║
|
|
|
|
|
|
║ └─ 发送UI打开事件 // EventManager.Send ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ 4. 【Update 阶段】- 运行时更新 ║
|
2025-09-10 21:02:34 +08:00
|
|
|
|
║ Update(dt) -> *OnUpdate(dt) // 每帧更新,处理UI逻辑(合并原 Update) ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 5. 【Refresh 阶段】- 数据刷新 ║
|
2025-09-10 21:02:34 +08:00
|
|
|
|
║ RefreshWithData(data) // 数据刷新(原 ReloadWindow) ║
|
|
|
|
|
|
║ └─ *OnDataRefresh(data) // 刷新UI内容,更新显示数据(原 OnReloadWindow) ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 6. 【Hide 阶段】- 隐藏 ║
|
|
|
|
|
|
║ HideWindow() -> Hide() ║
|
|
|
|
|
|
║ ├─ SetActive(false) // 隐藏GameObject ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ └─ *OnHide() // 隐藏回调 ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 7. 【Close 阶段】- 关闭销毁 ║
|
|
|
|
|
|
║ CloseWindow() -> DestroyWindow() ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ ├─ *OnHide() // 隐藏回调 ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ├─ *OnRelease() // 释放资源,清理引用 ║
|
|
|
|
|
|
║ ├─ Destroy(gameObject) // 销毁GameObject ║
|
|
|
|
|
|
║ └─ 卸载资源 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【当前架构特点】 ║
|
|
|
|
|
|
║ • 分离式设计: Init和Show独立调用,支持预初始化窗口 ║
|
|
|
|
|
|
║ • 使用方式: 先调用Init(data)初始化,再调用ShowWindow(data)显示 ║
|
|
|
|
|
|
║ • 灵活性: 可以先初始化多个窗口,根据需要选择性显示 ║
|
|
|
|
|
|
║ • 性能优化: 避免显示时的初始化卡顿,提升用户体验 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【子类需要关注的虚函数 - 标记为 * 的函数】 ║
|
|
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnBeforeInit(data) - 【可选重写】数据预处理 ║
|
|
|
|
|
|
║ • 时机:在 DoInit(AutoBindField、InitScreenAdaption)和 OnInit 之前调用 ║
|
|
|
|
|
|
║ • 用途:解析传入数据,设置初始状态,准备UI显示内容 ║
|
|
|
|
|
|
║ • 示例:解析OpenData,设置默认选中项,预加载必要资源 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:不需要调用 base.OnBeforeInit() ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnInit() - 【常用重写】UI初始化 ║
|
|
|
|
|
|
║ • 时机:在 DoInit(基础初始化)之后,窗口显示之前调用 ║
|
|
|
|
|
|
║ • 用途:初始化UI组件,绑定事件,设置默认值 ║
|
|
|
|
|
|
║ • 示例:按钮绑定,列表初始化,默认文本设置 ║
|
|
|
|
|
|
║ • 注意:不需要调用 base.OnInit() ║
|
|
|
|
|
|
║ ║
|
2025-09-11 16:51:41 +08:00
|
|
|
|
║ 🔸 *OnShow(data) - 【常用重写】显示时业务逻辑 ║
|
|
|
|
|
|
║ • 时机:窗口显示过程中调用,在SetActive之前 ║
|
|
|
|
|
|
║ • 用途:处理显示时的主要业务逻辑,数据刷新,UI更新 ║
|
|
|
|
|
|
║ • 示例:刷新列表数据,更新UI显示,准备动画数据 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:不需要调用 base.OnShow(data) ║
|
2025-09-11 16:51:41 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnAfterShow(data) - 【按需重写】显示后最终处理 ║
|
|
|
|
|
|
║ • 时机:窗口完全显示后调用,在SetActive之后 ║
|
|
|
|
|
|
║ • 用途:处理显示完成后的后续逻辑,启动动画,开始计时 ║
|
|
|
|
|
|
║ • 示例:播放入场动画,开始倒计时,发送显示完成事件 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:不需要调用 base.OnAfterShow(data) ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnUpdate(dt) - 【按需重写】每帧更新 ║
|
|
|
|
|
|
║ • 时机:每帧调用(仅在窗口激活且已创建时) ║
|
|
|
|
|
|
║ • 用途:处理需要持续更新的逻辑 ║
|
|
|
|
|
|
║ • 示例:倒计时更新,进度条刷新,实时数据显示 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:避免在此进行重度计算,影响性能 ,不需要调用 base.OnUpdate(dt) ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnDataRefresh(data) - 【按需重写】数据刷新 ║
|
|
|
|
|
|
║ • 时机:调用 RefreshWithData 时触发 ║
|
|
|
|
|
|
║ • 用途:更新已显示窗口的内容,不重新初始化 ║
|
|
|
|
|
|
║ • 示例:更新商品列表,刷新玩家信息,切换显示内容 ║
|
|
|
|
|
|
║ • 注意:通常不需要调用 base.OnDataRefresh(data) ║
|
|
|
|
|
|
║ ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ 🔸 *OnHide() - 【按需重写】隐藏时清理 ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ • 时机:窗口隐藏时调用 ║
|
|
|
|
|
|
║ • 用途:暂停逻辑,保存状态,停止动画 ║
|
|
|
|
|
|
║ • 示例:暂停倒计时,保存输入内容,停止音效 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:不需要调用 base.OnHide() ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 🔸 *OnRelease() - 【重要重写】资源释放 ║
|
|
|
|
|
|
║ • 时机:窗口销毁时调用 ║
|
|
|
|
|
|
║ • 用途:释放资源,取消订阅,清理引用 ║
|
|
|
|
|
|
║ • 示例:取消事件监听,释放Tween,清理对象池 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 注意:不需要调用 base.OnRelease() ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
║ 【其他说明】 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • AutoBindField: 自动绑定字段,由代码生成工具处理,不要手动重写 ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ • RefreshWithData: 数据刷新函数,窗口已初始化时调用OnDataRefresh,未初始化时报错 ║
|
|
|
|
|
|
║ • Init: 初始化函数,确保窗口只初始化一次,包含OnBeforeInit、DoInit、OnInit的完整流程 ║
|
|
|
|
|
|
║ • ShowWindow: 显示窗口的公共接口,内部调用私有的Show函数执行实际显示逻辑 ║
|
|
|
|
|
|
║ • 架构特点: Init和Show分离,支持窗口预初始化,然后在需要时显示 ║
|
2025-09-12 15:18:50 +08:00
|
|
|
|
║ • 重写虚函数时,不需要调用 base.OnXxx(),具体见上述说明 ║
|
2025-09-10 16:05:21 +08:00
|
|
|
|
║ ║
|
|
|
|
|
|
╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2025-09-10 21:02:34 +08:00
|
|
|
|
#region Private Helper Methods
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 绑定背景关闭按钮
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void _TryBindBgClose()
|
|
|
|
|
|
{
|
|
|
|
|
|
var trans = transform.Find("BgClose");
|
|
|
|
|
|
if (trans)
|
|
|
|
|
|
{
|
|
|
|
|
|
var btn = trans.GetComponent<Button>();
|
|
|
|
|
|
if (btn)
|
|
|
|
|
|
{
|
|
|
|
|
|
BindButton(btn, () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var clickAudio = btn.GetComponent<ClickAudio>();
|
|
|
|
|
|
if (clickAudio)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (clickAudio.IsPlayAudio && !string.IsNullOrEmpty(clickAudio.AudioKey))
|
2025-09-12 15:18:50 +08:00
|
|
|
|
{
|
2025-09-04 12:16:08 +08:00
|
|
|
|
AudioManager.Instance.PlayAudio(clickAudio.AudioKey);
|
2025-09-12 15:18:50 +08:00
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
CommonUtilsFramework.PlayUICommonSound();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (_onBgCloseFunc == null)
|
|
|
|
|
|
{
|
2025-09-11 21:06:09 +08:00
|
|
|
|
CloseWindow(UIWindowCloseType.HideAndDestroy);
|
2025-09-04 12:16:08 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
_onBgCloseFunc?.Invoke();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 21:02:34 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
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)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
2025-09-10 16:05:21 +08:00
|
|
|
|
OnBeforeInit(data);
|
|
|
|
|
|
if (isInited)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
2025-09-10 16:05:21 +08:00
|
|
|
|
DebugUtil.LogWarning("window : {0} already inited", WindowName);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DoInit();
|
2025-09-04 12:16:08 +08:00
|
|
|
|
OnInit();
|
2025-09-09 20:26:41 +08:00
|
|
|
|
isInited = true;
|
2025-09-04 12:16:08 +08:00
|
|
|
|
}
|
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)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 未被唤醒不执行Show
|
|
|
|
|
|
if (IsUnEnabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_isShow)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogWarning("window : {0} is show, can't show again", WindowName);
|
|
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
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 == 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2025-09-12 15:18:50 +08:00
|
|
|
|
_notchScreenAdapter?.UpdateCheck();
|
|
|
|
|
|
OnUpdate(dt);
|
2025-09-04 12:16:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
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>
|
2025-09-10 21:02:34 +08:00
|
|
|
|
public void RefreshWithData(object data)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isInited)
|
|
|
|
|
|
{
|
|
|
|
|
|
OnDataRefresh(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogError("window : {0} not inited", WindowName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-11 21:06:09 +08:00
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 隐藏窗口
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 关闭窗口
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="closeType">关闭类型</param>
|
2025-09-11 21:06:09 +08:00
|
|
|
|
public async void CloseWindow(UIWindowCloseType closeType)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
IsClosing = true;
|
|
|
|
|
|
DebugUtil.LogG($"关闭UI:{WindowName}, closeType{closeType}");
|
|
|
|
|
|
|
|
|
|
|
|
if (UIManager.Instance.CheckWindowIsFullScreen(this))
|
|
|
|
|
|
{
|
2025-09-11 21:06:09 +08:00
|
|
|
|
if (_shutMainCamera)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
2025-09-11 21:06:09 +08:00
|
|
|
|
CameraManager.Instance.SetMainCameraActive(true);
|
2025-09-04 12:16:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (closeType == UIWindowCloseType.HideAndDestroy)
|
|
|
|
|
|
{
|
|
|
|
|
|
var last = UIManager.Instance.GetLast();
|
|
|
|
|
|
if (last == this)
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogG($"PopWindow{this.WindowName}");
|
|
|
|
|
|
UIManager.Instance.PopWindow();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
|
2025-09-12 15:54:45 +08:00
|
|
|
|
if (UIManager.Instance.UiWindowStack.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (UIManager.Instance.CheckWindowIsFullScreen(this))
|
2025-09-12 15:18:50 +08:00
|
|
|
|
{
|
2025-09-12 15:54:45 +08:00
|
|
|
|
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--)
|
2025-09-12 15:18:50 +08:00
|
|
|
|
{
|
2025-09-12 15:54:45 +08:00
|
|
|
|
var latestWindow = UIManager.Instance.UiWindowStack[i];
|
|
|
|
|
|
latestWindow.ShowWindow();
|
|
|
|
|
|
|
|
|
|
|
|
if (UIManager.Instance.CheckWindowIsFullScreen(latestWindow))
|
|
|
|
|
|
break;
|
2025-09-12 15:18:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 15:54:45 +08:00
|
|
|
|
else
|
2025-09-12 15:18:50 +08:00
|
|
|
|
{
|
2025-09-12 15:54:45 +08:00
|
|
|
|
UIManager.Instance.ForceRemoveWindow(this);
|
2025-09-12 15:18:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 15:54:45 +08:00
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
|
2025-09-12 15:54:45 +08:00
|
|
|
|
bool isShowCloseAnim = IsShowOpenAnim;
|
2025-09-04 12:16:08 +08:00
|
|
|
|
if (isShowCloseAnim)
|
|
|
|
|
|
{
|
2025-09-12 15:18:50 +08:00
|
|
|
|
UIManager.Instance.BlockUIForCloseOperation();
|
2025-09-04 12:16:08 +08:00
|
|
|
|
await AnimHide(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
DestroyWindow();
|
|
|
|
|
|
UIManager.Instance.RemoveWindow(mWindowName);
|
|
|
|
|
|
IsClosing = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UIManager.Instance.RemoveWindow(mWindowName);
|
|
|
|
|
|
DestroyWindow();
|
|
|
|
|
|
IsClosing = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-12 15:18:50 +08:00
|
|
|
|
else if (closeType == UIWindowCloseType.ForceDestroy)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
2025-09-12 15:18:50 +08:00
|
|
|
|
// 强制清除所有界面时使用
|
2025-09-04 12:16:08 +08:00
|
|
|
|
DestroyWindow();
|
|
|
|
|
|
UIManager.Instance.RemoveWindow(mWindowName);
|
|
|
|
|
|
IsClosing = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-10 21:02:34 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
#region Internal Implementation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 执行基础初始化
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void DoInit()
|
|
|
|
|
|
{
|
|
|
|
|
|
_isShow = false;
|
|
|
|
|
|
_shutMainCamera = UIManager.Instance.IsShutMainCamera(WindowName);
|
|
|
|
|
|
IsShowOpenAnim = UIManager.Instance.GetIsAutoPlayAnim(WindowName);
|
|
|
|
|
|
AutoBindField();
|
|
|
|
|
|
InitScreenAdaption();
|
|
|
|
|
|
_TryBindBgClose();
|
|
|
|
|
|
}
|
2025-09-10 21:02:34 +08:00
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 执行显示逻辑
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-10 19:54:45 +08:00
|
|
|
|
private void DoShow()
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (UIManager.Instance.WindowInfos.TryGetValue(WindowName, out var windowInfo))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CameraManager.Instance.CheckMainCameraIsActive())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (windowInfo.UIOpenType == UIOpenType.FullScreen)
|
|
|
|
|
|
{
|
2025-09-12 15:18:50 +08:00
|
|
|
|
// 特殊处理主界面
|
2025-09-11 21:06:09 +08:00
|
|
|
|
if (_shutMainCamera && WindowName != UINameConst.UI_MainPanel)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
CameraManager.Instance.SetMainCameraActive(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 销毁窗口
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void DestroyWindow()
|
|
|
|
|
|
{
|
|
|
|
|
|
DebugUtil.LogG($"DestroyWindow:{WindowName}");
|
2025-09-12 15:18:50 +08:00
|
|
|
|
OnHide();
|
2025-09-12 16:28:11 +08:00
|
|
|
|
gameObject?.SetActive(false);
|
|
|
|
|
|
_isShow = false;
|
|
|
|
|
|
EventManager.Instance.Send(EventManager.EventName.UIHide, WindowName);
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
if (gameObject)
|
|
|
|
|
|
{
|
2025-09-09 20:26:41 +08:00
|
|
|
|
if (isInited)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
OnRelease();
|
2025-09-12 15:18:50 +08:00
|
|
|
|
DoRelease();
|
2025-09-09 20:26:41 +08:00
|
|
|
|
isInited = false;
|
2025-09-04 12:16:08 +08:00
|
|
|
|
}
|
2025-09-12 15:18:50 +08:00
|
|
|
|
if (UIManager.Instance.UIWindowObjDic.ContainsKey(gameObject))
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
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
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 基础资源释放
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
private void DoRelease()
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
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;
|
2025-09-04 12:16:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-09-12 15:18:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Virtual Methods
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
// Init Phase
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 初始化前预处理
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-10 19:54:45 +08:00
|
|
|
|
protected virtual void OnBeforeInit(object data = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// UI初始化
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
public virtual void OnInit(){}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 自动绑定字段
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected virtual void AutoBindField()
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
}
|
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-12 15:18:50 +08:00
|
|
|
|
protected virtual void OnShow(object data)
|
2025-09-11 16:39:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 显示后处理
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
protected virtual void OnAfterShow(object data)
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-09-12 15:18:50 +08:00
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 每帧更新
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
protected virtual void OnUpdate(float dt)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Refresh Phase
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 数据刷新
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
protected virtual void OnDataRefresh(object data) { }
|
|
|
|
|
|
|
|
|
|
|
|
// Hide Phase
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 隐藏时处理
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
protected virtual void OnHide()
|
2025-09-04 12:16:08 +08:00
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 15:18:50 +08:00
|
|
|
|
// Release Phase
|
|
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// <summary>
|
2025-09-12 15:18:50 +08:00
|
|
|
|
/// 资源释放
|
2025-09-04 12:16:08 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
public virtual void OnRelease()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-09-12 15:18:50 +08:00
|
|
|
|
|
2025-09-04 12:16:08 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|