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