feat(ui): 添加UI路由栈状态查询功能

- 在Push方法中添加栈顶检查,避免重复推送相同UI并记录警告日志
- 移除GetCurrentUiKey私有方法,使用Peek方法替代
- 添加Peek方法获取栈顶UI的类型名称
- 添加IsTop方法判断指定UI是否为栈顶元素
- 添加Contains方法检查UI是否存在于栈中
- 添加Count属性获取栈中元素数量
- 更新IUiRouter接口定义相关方法
- 简化DoClearInternal方法实现逻辑
This commit is contained in:
GeWuYou 2026-01-19 21:05:13 +08:00
parent 766a73f2a9
commit 859bd1de41
2 changed files with 67 additions and 15 deletions

View File

@ -8,6 +8,11 @@ namespace GFramework.Game.Abstractions.ui;
/// </summary>
public interface IUiRouter : ISystem
{
/// <summary>
/// 获取当前UI栈深度
/// </summary>
int Count { get; }
/// <summary>
/// 绑定UI根节点
/// </summary>
@ -61,4 +66,20 @@ public interface IUiRouter : ISystem
/// </summary>
/// <param name="handler">处理器实例</param>
void UnregisterHandler(IUiTransitionHandler handler);
/// <summary>
/// 获取当前栈顶UI的Key
/// </summary>
/// <returns>当前UI Key如果栈为空返回空字符串</returns>
string Peek();
/// <summary>
/// 判断指定UI是否为当前栈顶UI
/// </summary>
bool IsTop(string uiKey);
/// <summary>
/// 判断指定UI是否存在于UI栈中
/// </summary>
bool Contains(string uiKey);
}

View File

@ -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);
}
/// <summary>
/// 获取栈顶元素的视图类型名称
/// </summary>
/// <returns>如果栈为空则返回空字符串,否则返回栈顶元素视图类型的名称</returns>
public string Peek()
{
return _stack.Count == 0 ? string.Empty : _stack.Peek().View.GetType().Name;
}
/// <summary>
/// 判断栈顶元素是否指定的UI类型
/// </summary>
/// <param name="uiKey">要比较的UI类型名称</param>
/// <returns>如果栈为空或栈顶元素类型不匹配则返回false否则返回true</returns>
public bool IsTop(string uiKey)
{
if (_stack.Count == 0)
return false;
return _stack.Peek().View.GetType().Name == uiKey;
}
/// <summary>
/// 判断栈中是否包含指定类型的UI元素
/// </summary>
/// <param name="uiKey">要查找的UI类型名称</param>
/// <returns>如果栈中存在指定类型的UI元素则返回true否则返回false</returns>
public bool Contains(string uiKey)
{
return _stack.Any(p => p.View.GetType().Name == uiKey);
}
/// <summary>
/// 获取栈中元素的数量
/// </summary>
public int Count => _stack.Count;
/// <summary>
/// 初始化方法在页面初始化时获取UI工厂实例
/// </summary>
@ -172,18 +213,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
/// </summary>
protected abstract void RegisterHandlers();
/// <summary>
/// 获取当前栈顶UI的key
/// </summary>
/// <returns>当前UI key如果栈为空则返回空字符串</returns>
private string GetCurrentUiKey()
{
if (_stack.Count == 0)
return string.Empty;
var page = _stack.Peek();
return page.View.GetType().Name;
}
/// <summary>
/// 创建UI切换事件
/// </summary>
@ -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
/// <summary>
/// 执行Clear的核心逻辑不触发Pipeline
/// </summary>
/// <param name="policy">UI弹出策略</param>
private void DoClearInternal(UiPopPolicy policy)
{
Log.Debug("Clear UI Stack internal, count={0}", _stack.Count);
// 循环执行弹出操作直到栈为空
while (_stack.Count > 0)
DoPopInternal(policy);
}