From 859bd1de41b98a114ccea1270dcca87218fdf735 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Mon, 19 Jan 2026 21:05:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=B7=BB=E5=8A=A0UI=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E6=A0=88=E7=8A=B6=E6=80=81=E6=9F=A5=E8=AF=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在Push方法中添加栈顶检查,避免重复推送相同UI并记录警告日志 - 移除GetCurrentUiKey私有方法,使用Peek方法替代 - 添加Peek方法获取栈顶UI的类型名称 - 添加IsTop方法判断指定UI是否为栈顶元素 - 添加Contains方法检查UI是否存在于栈中 - 添加Count属性获取栈中元素数量 - 更新IUiRouter接口定义相关方法 - 简化DoClearInternal方法实现逻辑 --- GFramework.Game.Abstractions/ui/IUiRouter.cs | 21 +++++++ GFramework.Game/ui/UiRouterBase.cs | 61 +++++++++++++++----- 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/GFramework.Game.Abstractions/ui/IUiRouter.cs b/GFramework.Game.Abstractions/ui/IUiRouter.cs index e1bad8e..e311bad 100644 --- a/GFramework.Game.Abstractions/ui/IUiRouter.cs +++ b/GFramework.Game.Abstractions/ui/IUiRouter.cs @@ -8,6 +8,11 @@ namespace GFramework.Game.Abstractions.ui; /// public interface IUiRouter : ISystem { + /// + /// 获取当前UI栈深度 + /// + int Count { get; } + /// /// 绑定UI根节点 /// @@ -61,4 +66,20 @@ public interface IUiRouter : ISystem /// /// 处理器实例 void UnregisterHandler(IUiTransitionHandler handler); + + /// + /// 获取当前栈顶UI的Key + /// + /// 当前UI Key,如果栈为空返回空字符串 + string Peek(); + + /// + /// 判断指定UI是否为当前栈顶UI + /// + bool IsTop(string uiKey); + + /// + /// 判断指定UI是否存在于UI栈中 + /// + bool Contains(string uiKey); } \ No newline at end of file diff --git a/GFramework.Game/ui/UiRouterBase.cs b/GFramework.Game/ui/UiRouterBase.cs index 99e8cc4..d776a2e 100644 --- a/GFramework.Game/ui/UiRouterBase.cs +++ b/GFramework.Game/ui/UiRouterBase.cs @@ -71,6 +71,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter UiTransitionPolicy policy = UiTransitionPolicy.Exclusive ) { + if (IsTop(uiKey)) + { + Log.Warn("Push ignored: UI already on top: {0}", uiKey); + return; + } + var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param); Log.Debug( @@ -79,9 +85,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter ); BeforeChange(@event); - DoPushInternal(uiKey, param, policy); - AfterChange(@event); } @@ -157,6 +161,43 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter AfterChange(@event); } + /// + /// 获取栈顶元素的视图类型名称 + /// + /// 如果栈为空则返回空字符串,否则返回栈顶元素视图类型的名称 + public string Peek() + { + return _stack.Count == 0 ? string.Empty : _stack.Peek().View.GetType().Name; + } + + /// + /// 判断栈顶元素是否指定的UI类型 + /// + /// 要比较的UI类型名称 + /// 如果栈为空或栈顶元素类型不匹配则返回false,否则返回true + public bool IsTop(string uiKey) + { + if (_stack.Count == 0) + return false; + + return _stack.Peek().View.GetType().Name == uiKey; + } + + /// + /// 判断栈中是否包含指定类型的UI元素 + /// + /// 要查找的UI类型名称 + /// 如果栈中存在指定类型的UI元素则返回true,否则返回false + public bool Contains(string uiKey) + { + return _stack.Any(p => p.View.GetType().Name == uiKey); + } + + /// + /// 获取栈中元素的数量 + /// + public int Count => _stack.Count; + /// /// 初始化方法,在页面初始化时获取UI工厂实例 /// @@ -172,18 +213,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// protected abstract void RegisterHandlers(); - /// - /// 获取当前栈顶UI的key - /// - /// 当前UI key,如果栈为空则返回空字符串 - private string GetCurrentUiKey() - { - if (_stack.Count == 0) - return string.Empty; - var page = _stack.Peek(); - return page.View.GetType().Name; - } - /// /// 创建UI切换事件 /// @@ -196,7 +225,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter { return new UiTransitionEvent { - FromUiKey = GetCurrentUiKey(), + FromUiKey = Peek(), ToUiKey = toUiKey, TransitionType = type, Policy = policy ?? UiTransitionPolicy.Exclusive, @@ -310,9 +339,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter /// /// 执行Clear的核心逻辑(不触发Pipeline) /// + /// UI弹出策略 private void DoClearInternal(UiPopPolicy policy) { Log.Debug("Clear UI Stack internal, count={0}", _stack.Count); + // 循环执行弹出操作直到栈为空 while (_stack.Count > 0) DoPopInternal(policy); }