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);
}