diff --git a/GFramework.Game.Abstractions/ui/UiHandle.cs b/GFramework.Game.Abstractions/ui/UiHandle.cs
index a441ad3..c10e8b9 100644
--- a/GFramework.Game.Abstractions/ui/UiHandle.cs
+++ b/GFramework.Game.Abstractions/ui/UiHandle.cs
@@ -41,7 +41,7 @@ public readonly struct UiHandle
/// UI的键值,用于标识UI的类型或名称。
/// UI实例的唯一标识符。
/// UI所在的层级,用于控制UI的显示顺序。
- internal UiHandle(string key, string instanceId, UiLayer layer)
+ public UiHandle(string key, string instanceId, UiLayer layer)
{
Key = key;
InstanceId = instanceId;
diff --git a/GFramework.Game/ui/UiRouterBase.cs b/GFramework.Game/ui/UiRouterBase.cs
index 0449368..ded1226 100644
--- a/GFramework.Game/ui/UiRouterBase.cs
+++ b/GFramework.Game/ui/UiRouterBase.cs
@@ -21,6 +21,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
///
/// 层级管理(非栈层级),用于Overlay、Modal、Toast等浮层
+ /// Key: UiLayer, Value: Dictionary of InstanceId -> PageBehavior
///
private readonly Dictionary> _layers = new();
@@ -39,13 +40,16 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
///
private IUiFactory _factory = null!;
+ ///
+ /// 实例ID计数器,用于生成唯一ID
+ ///
+ private int _instanceCounter;
+
private IUiRoot _uiRoot = null!;
///
/// 注册UI切换处理器
///
- /// 处理器实例
- /// 执行选项
public void RegisterHandler(IUiTransitionHandler handler, UiTransitionHandlerOptions? options = null)
{
_pipeline.RegisterHandler(handler, options);
@@ -54,7 +58,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
///
/// 注销UI切换处理器
///
- /// 处理器实例
public void UnregisterHandler(IUiTransitionHandler handler)
{
_pipeline.UnregisterHandler(handler);
@@ -69,13 +72,11 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
Log.Debug("Bind UI Root: {0}", root.GetType().Name);
}
+ #region Page Stack Management
///
- /// 将指定的UI界面压入路由栈,显示新的UI界面
+ /// 将指定的UI界面压入路由栈
///
- /// UI界面的唯一标识符
- /// 进入界面的参数,可为空
- /// 界面切换策略,默认为Exclusive(独占)
public void Push(string uiKey, IUiPageEnterParam? param = null,
UiTransitionPolicy policy = UiTransitionPolicy.Exclusive)
{
@@ -86,11 +87,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param);
-
- Log.Debug(
- "Push UI Page: key={0}, policy={1}, stackBefore={2}",
- uiKey, policy, _stack.Count
- );
+ Log.Debug("Push UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count);
BeforeChange(@event);
DoPushPageInternal(uiKey, param, policy);
@@ -98,18 +95,12 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
///
- /// 将已存在的UI页面压入栈顶并显示
+ /// 将已存在的UI页面压入栈顶
///
- /// 已创建的UI页面行为实例
- /// 页面进入参数,可为空
- /// 页面切换策略
- public void Push(
- IUiPageBehavior page,
- IUiPageEnterParam? param = null,
- UiTransitionPolicy policy = UiTransitionPolicy.Exclusive
- )
+ public void Push(IUiPageBehavior page, IUiPageEnterParam? param = null,
+ UiTransitionPolicy policy = UiTransitionPolicy.Exclusive)
{
- var uiKey = page.View.GetType().Name;
+ var uiKey = page.Key;
if (IsTop(uiKey))
{
@@ -118,11 +109,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
var @event = CreateEvent(uiKey, UiTransitionType.Push, policy, param);
-
- Log.Debug(
- "Push existing UI Page: key={0}, policy={1}, stackBefore={2}",
- uiKey, policy, _stack.Count
- );
+ Log.Debug("Push existing UI Page: key={0}, policy={1}, stackBefore={2}", uiKey, policy, _stack.Count);
BeforeChange(@event);
DoPushPageInternal(page, param, policy);
@@ -130,9 +117,8 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
///
- /// 弹出栈顶页面并根据策略处理页面
+ /// 弹出栈顶页面
///
- /// 弹出策略,默认为销毁策略
public void Pop(UiPopPolicy policy = UiPopPolicy.Destroy)
{
if (_stack.Count == 0)
@@ -149,175 +135,350 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
return;
}
- // ⚠️ 注意:nextUiKey 现在是可选的
- var nextUiKey = _stack.Count > 1
- ? _stack.ElementAt(1).Key
- : null;
-
- var @event = CreateEvent(
- nextUiKey,
- UiTransitionType.Pop
- );
+ var nextUiKey = _stack.Count > 1 ? _stack.ElementAt(1).Key : null;
+ var @event = CreateEvent(nextUiKey, UiTransitionType.Pop);
BeforeChange(@event);
-
DoPopInternal(policy);
-
AfterChange(@event);
}
-
///
/// 替换当前所有页面为新页面(基于uiKey)
///
- /// 新UI页面标识符
- /// 页面进入参数,可为空
- /// 弹出页面时的销毁策略,默认为销毁
- /// 推入页面时的过渡策略,默认为独占
- public void Replace(
- string uiKey,
- IUiPageEnterParam? param = null,
+ public void Replace(string uiKey, IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive)
{
var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param);
- Log.Debug(
- "Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}",
- uiKey, popPolicy, pushPolicy
- );
+ Log.Debug("Replace UI Stack with page: key={0}, popPolicy={1}, pushPolicy={2}", uiKey, popPolicy, pushPolicy);
BeforeChange(@event);
-
- // 使用内部方法清空栈,避免触发额外的Pipeline
DoClearInternal(popPolicy);
- // 使用工厂的增强方法获取实例
var page = _factory.Create(uiKey);
Log.Debug("Get/Create UI Page instance for Replace: {0}", page.GetType().Name);
DoPushPageInternal(page, param, pushPolicy);
-
AfterChange(@event);
}
///
- /// 替换当前所有页面为已存在的页面(基于实例)
+ /// 替换当前所有页面为已存在的页面
///
- /// 已创建的UI页面行为实例
- /// 页面进入参数,可为空
- /// 弹出页面时的销毁策略,默认为销毁
- /// 推入页面时的过渡策略,默认为独占
- public void Replace(
- IUiPageBehavior page,
- IUiPageEnterParam? param = null,
+ public void Replace(IUiPageBehavior page, IUiPageEnterParam? param = null,
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive)
{
var uiKey = page.Key;
var @event = CreateEvent(uiKey, UiTransitionType.Replace, pushPolicy, param);
-
- Log.Debug(
- "Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}",
- uiKey, popPolicy, pushPolicy
- );
+ Log.Debug("Replace UI Stack with existing page: key={0}, popPolicy={1}, pushPolicy={2}",
+ uiKey, popPolicy, pushPolicy);
BeforeChange(@event);
-
- // 清空栈
DoClearInternal(popPolicy);
-
Log.Debug("Use existing UI Page instance for Replace: {0}", page.GetType().Name);
DoPushPageInternal(page, param, pushPolicy);
-
AfterChange(@event);
}
///
- /// 清空所有页面栈中的页面
+ /// 清空所有页面栈
///
public void Clear()
{
var @event = CreateEvent(string.Empty, UiTransitionType.Clear);
-
Log.Debug("Clear UI Stack, stackCount={0}", _stack.Count);
BeforeChange(@event);
-
- // 使用内部方法,避免触发额外的Pipeline
DoClearInternal(UiPopPolicy.Destroy);
-
AfterChange(@event);
}
-
///
- /// 获取页面栈顶元素的键值,但不移除该元素
+ /// 获取栈顶元素的键值
///
- /// 如果页面栈为空则返回空字符串,否则返回栈顶元素的键值
public string PeekKey()
{
return _stack.Count == 0 ? string.Empty : _stack.Peek().Key;
}
///
- /// 获取页面栈顶元素,但不移除该元素
+ /// 获取栈顶元素
///
- /// 返回栈顶的IUiPageBehavior元素
public IUiPageBehavior? Peek()
{
return _stack.Count == 0 ? null : _stack.Peek();
}
-
///
- /// 判断栈顶元素是否指定的UI类型
+ /// 判断栈顶是否为指定UI
///
- /// 要比较的UI类型名称
- /// 如果栈为空或栈顶元素类型不匹配则返回false,否则返回true
public bool IsTop(string uiKey)
{
return _stack.Count != 0 && _stack.Peek().Key.Equals(uiKey);
}
///
- /// 判断栈中是否包含指定类型的UI元素
+ /// 判断栈中是否包含指定UI
///
- /// 要查找的UI类型名称
- /// 如果栈中存在指定类型的UI元素则返回true,否则返回false
public bool Contains(string uiKey)
{
return _stack.Any(p => p.Key.Equals(uiKey));
}
///
- /// 获取栈中元素的数量
+ /// 获取栈深度
///
public int Count => _stack.Count;
+ #endregion
+
+ #region Layer UI Management
+
///
- /// 初始化方法,在页面初始化时获取UI工厂实例
+ /// 在指定层级显示UI(基于 uiKey)
+ ///
+ public UiHandle Show(string uiKey, UiLayer layer, IUiPageEnterParam? param = null)
+ {
+ if (layer == UiLayer.Page)
+ throw new ArgumentException("Use Push() for Page layer");
+
+ // 创建实例
+ var page = _factory.Create(uiKey);
+
+ return ShowInternal(page, layer, param);
+ }
+
+ ///
+ /// 在指定层级显示UI(基于实例)
+ ///
+ public UiHandle Show(IUiPageBehavior page, UiLayer layer)
+ {
+ if (layer == UiLayer.Page)
+ throw new ArgumentException("Use Push() for Page layer");
+
+ return ShowInternal(page, layer, null);
+ }
+
+ ///
+ /// 隐藏指定层级的UI
+ ///
+ public void Hide(UiHandle handle, UiLayer layer, bool destroy = false)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return;
+
+ if (!layerDict.TryGetValue(handle.InstanceId, out var page))
+ return;
+
+ if (destroy)
+ {
+ page.OnExit();
+ _uiRoot.RemoveUiPage(page);
+ layerDict.Remove(handle.InstanceId);
+ Log.Debug("Hide & Destroy UI: instanceId={0}, layer={1}", handle.InstanceId, layer);
+ }
+ else
+ {
+ page.OnHide();
+ Log.Debug("Hide UI (suspend): instanceId={0}, layer={1}", handle.InstanceId, layer);
+ }
+ }
+
+ ///
+ /// 恢复指定UI的显示
+ ///
+ public void Resume(UiHandle handle, UiLayer layer)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return;
+
+ if (!layerDict.TryGetValue(handle.InstanceId, out var page))
+ return;
+
+ page.OnShow();
+ page.OnResume();
+ Log.Debug("Resume UI: instanceId={0}, layer={1}", handle.InstanceId, layer);
+ }
+
+ ///
+ /// 清空指定层级的所有UI
+ ///
+ public void ClearLayer(UiLayer layer, bool destroy = false)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return;
+
+ var handles = layerDict.Keys
+ .Select(instanceId =>
+ {
+ var page = layerDict[instanceId];
+ return new UiHandle(page.Key, instanceId, layer);
+ })
+ .ToArray();
+
+ foreach (var handle in handles)
+ Hide(handle, layer, destroy);
+
+ Log.Debug("Cleared layer: {0}, destroyed={1}", layer, destroy);
+ }
+
+ ///
+ /// 获取指定层级的UI实例
+ ///
+ public UiHandle? GetFromLayer(UiHandle handle, UiLayer layer)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return null;
+
+ return layerDict.ContainsKey(handle.InstanceId) ? handle : null;
+ }
+
+ ///
+ /// 获取指定 uiKey 在指定层级的所有实例
+ ///
+ public IReadOnlyList GetAllFromLayer(string uiKey, UiLayer layer)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return Array.Empty();
+
+ return layerDict
+ .Where(kvp => kvp.Value.Key.Equals(uiKey))
+ .Select(kvp => new UiHandle(uiKey, kvp.Key, layer))
+ .ToList();
+ }
+
+ ///
+ /// 判断指定UI是否在层级中可见
+ ///
+ public bool HasVisibleInLayer(UiHandle handle, UiLayer layer)
+ {
+ if (!_layers.TryGetValue(layer, out var layerDict))
+ return false;
+
+ if (!layerDict.TryGetValue(handle.InstanceId, out var page))
+ return false;
+
+ return page.IsVisible;
+ }
+
+ #endregion
+
+ #region Route Guards
+
+ ///
+ /// 注册路由守卫
+ ///
+ public void AddGuard(IUiRouteGuard guard)
+ {
+ ArgumentNullException.ThrowIfNull(guard);
+
+ if (_guards.Contains(guard))
+ {
+ Log.Debug("Guard already registered: {0}", guard.GetType().Name);
+ return;
+ }
+
+ _guards.Add(guard);
+ _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority));
+ Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority);
+ }
+
+ ///
+ /// 注册路由守卫(泛型)
+ ///
+ public void AddGuard() where T : IUiRouteGuard, new()
+ {
+ AddGuard(new T());
+ }
+
+ ///
+ /// 移除路由守卫
+ ///
+ public void RemoveGuard(IUiRouteGuard guard)
+ {
+ ArgumentNullException.ThrowIfNull(guard);
+ if (_guards.Remove(guard))
+ Log.Debug("Guard removed: {0}", guard.GetType().Name);
+ }
+
+ #endregion
+
+ #region Initialization
+
+ ///
+ /// 初始化函数,在对象创建时调用。
+ /// 该函数负责获取UI工厂实例并注册处理程序。
///
protected override void OnInit()
{
+ // 获取UI工厂实例,并确保其不为null
_factory = this.GetUtility()!;
+
+ // 输出调试日志,记录UI路由器基类已初始化及使用的工厂类型
Log.Debug("UiRouterBase initialized. Factory={0}", _factory.GetType().Name);
+
+ // 调用抽象方法以注册具体的处理程序
RegisterHandlers();
}
///
- /// 注册默认的UI切换处理器
+ /// 抽象方法,用于注册具体的处理程序。
+ /// 子类必须实现此方法以完成特定的处理逻辑注册。
///
protected abstract void RegisterHandlers();
+ #endregion
+
+ #region Internal Helpers
+
///
- /// 创建UI切换事件
+ /// 生成唯一实例ID
///
- private UiTransitionEvent CreateEvent(
- string? toUiKey,
- UiTransitionType type,
- UiTransitionPolicy? policy = null,
- IUiPageEnterParam? param = null
- )
+ private string GenerateInstanceId()
+ {
+ return $"ui_{++_instanceCounter:D6}";
+ }
+
+ ///
+ /// 内部Show实现,支持重入
+ ///
+ private UiHandle ShowInternal(IUiPageBehavior page, UiLayer layer, IUiPageEnterParam? param)
+ {
+ var instanceId = GenerateInstanceId();
+ var handle = new UiHandle(page.Key, instanceId, layer);
+
+ // 初始化层级字典
+ if (!_layers.ContainsKey(layer))
+ _layers[layer] = new Dictionary();
+
+ var layerDict = _layers[layer];
+
+ // 检查重入性
+ if (!page.IsReentrant && layerDict.Values.Any(p => p.Key == page.Key))
+ {
+ Log.Warn("UI {0} is not reentrant but already exists in layer {1}", page.Key, layer);
+ throw new InvalidOperationException(
+ $"UI {page.Key} does not support multiple instances in layer {layer}");
+ }
+
+ // 添加到层级管理
+ layerDict[instanceId] = page;
+
+ // 添加到UiRoot
+ _uiRoot.AddUiPage(page, layer);
+
+ // 生命周期
+ page.OnEnter(param);
+ page.OnShow();
+
+ Log.Debug("Show UI: key={0}, instanceId={1}, layer={2}", page.Key, instanceId, layer);
+ return handle;
+ }
+
+ private UiTransitionEvent CreateEvent(string? toUiKey, UiTransitionType type,
+ UiTransitionPolicy? policy = null, IUiPageEnterParam? param = null)
{
return new UiTransitionEvent
{
@@ -329,9 +490,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
};
}
- ///
- /// 执行UI切换前的Handler(阻塞)
- ///
private void BeforeChange(UiTransitionEvent @event)
{
Log.Debug("BeforeChange phases started: {0}", @event.TransitionType);
@@ -339,9 +497,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
Log.Debug("BeforeChange phases completed: {0}", @event.TransitionType);
}
- ///
- /// 执行UI切换后的Handler(不阻塞)
- ///
private void AfterChange(UiTransitionEvent @event)
{
Log.Debug("AfterChange phases started: {0}", @event.TransitionType);
@@ -359,31 +514,21 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
});
}
- ///
- /// 执行Push页面的核心逻辑(基于 uiKey)
- ///
private void DoPushPageInternal(string uiKey, IUiPageEnterParam? param, UiTransitionPolicy policy)
{
- // 执行进入守卫
if (!ExecuteEnterGuardsAsync(uiKey, param).GetAwaiter().GetResult())
{
Log.Warn("Push blocked by guard: {0}", uiKey);
return;
}
- // 使用工厂的增强方法获取实例
var page = _factory.Create(uiKey);
Log.Debug("Get/Create UI Page instance: {0}", page.GetType().Name);
-
DoPushPageInternal(page, param, policy);
}
- ///
- /// 执行Push页面的核心逻辑(基于 page)
- ///
private void DoPushPageInternal(IUiPageBehavior page, IUiPageEnterParam? param, UiTransitionPolicy policy)
{
- // 1. 处理当前栈顶页面
if (_stack.Count > 0)
{
var current = _stack.Peek();
@@ -397,273 +542,54 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
}
}
- // 2. 将新页面添加到UiRoot
Log.Debug("Add page to UiRoot: {0}", page.View.GetType().Name);
_uiRoot.AddUiPage(page);
- // 3. 压入栈
_stack.Push(page);
- // 4. 触发页面生命周期
- Log.Debug(
- "Enter & Show page: {0}, stackAfter={1}",
- page.View.GetType().Name, _stack.Count
- );
-
+ Log.Debug("Enter & Show page: {0}, stackAfter={1}", page.View.GetType().Name, _stack.Count);
page.OnEnter(param);
page.OnShow();
}
- ///
- /// 执行Pop的核心逻辑(不触发Pipeline)
- ///
private void DoPopInternal(UiPopPolicy policy)
{
if (_stack.Count == 0)
return;
var top = _stack.Pop();
-
- Log.Debug(
- "Pop UI Page internal: {0}, policy={1}, stackAfterPop={2}",
- top.GetType().Name, policy, _stack.Count
- );
+ Log.Debug("Pop UI Page internal: {0}, policy={1}, stackAfterPop={2}",
+ top.GetType().Name, policy, _stack.Count);
if (policy == UiPopPolicy.Destroy)
{
top.OnExit();
_uiRoot.RemoveUiPage(top);
}
- else // Suspend
+ else
{
top.OnHide();
}
- if (_stack.Count <= 0) return;
- var next = _stack.Peek();
- next.OnResume();
- next.OnShow();
+ if (_stack.Count > 0)
+ {
+ var next = _stack.Peek();
+ next.OnResume();
+ next.OnShow();
+ }
}
- ///
- /// 执行Clear的核心逻辑(不触发Pipeline)
- ///
- /// UI弹出策略
private void DoClearInternal(UiPopPolicy policy)
{
Log.Debug("Clear UI Stack internal, count={0}", _stack.Count);
- // 循环执行弹出操作直到栈为空
while (_stack.Count > 0)
DoPopInternal(policy);
}
- #region 层级管理
-
- ///
- /// 在指定层级显示UI(非栈管理)
- ///
- public void Show(
- string uiKey,
- UiLayer layer,
- IUiPageEnterParam? param = null)
- {
- if (layer == UiLayer.Page) throw new ArgumentException("Use Push() for Page layer");
-
- // 初始化层级字典
- if (!_layers.ContainsKey(layer))
- _layers[layer] = new Dictionary();
-
- var layerDict = _layers[layer];
-
- // 检查是否已存在
- if (layerDict.TryGetValue(uiKey, out var existing))
- {
- Log.Debug("UI already visible in layer: {0}, layer={1}", uiKey, layer);
- existing.OnEnter(param);
- existing.OnShow();
- return;
- }
-
- // 获取或创建实例
- var page = _factory.Create(uiKey);
- layerDict[uiKey] = page;
-
- // 添加到UiRoot,传入层级Z-order
- _uiRoot.AddUiPage(page, layer);
-
- page.OnEnter(param);
- page.OnShow();
-
- Log.Debug("Show UI in layer: {0}, layer={1}", uiKey, layer);
- }
-
- ///
- /// 在指定层级显示UI(基于实例)
- ///
- public void Show(IUiPageBehavior page, UiLayer layer)
- {
- if (layer == UiLayer.Page)
- throw new ArgumentException("Use Push() for Page layer");
-
- var uiKey = page.Key;
-
- if (!_layers.ContainsKey(layer))
- _layers[layer] = new Dictionary();
-
- _layers[layer][uiKey] = page;
- _uiRoot.AddUiPage(page, layer);
- page.OnShow();
-
- Log.Debug("Show existing UI instance in layer: {0}, layer={1}", uiKey, layer);
- }
-
- ///
- /// 隐藏指定层级的UI。
- ///
- /// 要隐藏的UI的唯一标识符。
- /// UI所在的层级。
- /// 是否永久销毁UI。如果为true,则UI将被彻底移除;如果为false,则UI仅被隐藏,可后续恢复。
- public void Hide(string uiKey, UiLayer layer, bool destroy = false)
- {
- // 尝试获取指定层级的UI字典,若不存在则直接返回
- if (!_layers.TryGetValue(layer, out var layerDict))
- return;
-
- // 尝试获取指定UI键对应的页面对象,若不存在则直接返回
- if (!layerDict.TryGetValue(uiKey, out var page))
- return;
-
- if (destroy)
- {
- // 永久移除UI:调用OnExit方法并从UI根节点和层级字典中移除该UI
- page.OnExit(); // ✅ 只在 Destroy 时 Exit
- _uiRoot.RemoveUiPage(page);
- layerDict.Remove(uiKey);
-
- Log.Debug(
- "Hide & Destroy UI from layer: {0}, layer={1}",
- uiKey, layer
- );
- }
- else
- {
- // 临时隐藏UI:调用OnHide方法,保留UI状态以便后续恢复
- page.OnHide(); // ✅ Hide ≠ Exit
-
- Log.Debug(
- "Hide UI from layer (suspend): {0}, layer={1}",
- uiKey, layer
- );
- }
- }
-
- ///
- /// 恢复指定层级中已隐藏的UI。
- ///
- /// 要恢复的UI的唯一标识符。
- /// UI所在的层级。
- public void Resume(string uiKey, UiLayer layer)
- {
- // 尝试获取指定层级的UI字典,若不存在则直接返回
- if (!_layers.TryGetValue(layer, out var layerDict))
- return;
-
- // 尝试获取指定UI键对应的页面对象,若不存在则直接返回
- if (!layerDict.TryGetValue(uiKey, out var page))
- return;
-
- // 调用OnShow和OnResume方法以恢复UI的显示和状态
- page.OnShow();
- page.OnResume();
-
- Log.Debug("Resume UI in layer: {0}, layer={1}", uiKey, layer);
- }
-
- ///
- /// 清空指定层级的所有UI
- ///
- public void ClearLayer(UiLayer layer, bool destroy = false)
- {
- if (!_layers.TryGetValue(layer, out var layerDict))
- return;
-
- var keys = layerDict.Keys.ToArray();
- foreach (var key in keys) Hide(key, layer, destroy);
-
- Log.Debug("Cleared layer: {0}, destroyed={1}", layer, destroy);
- }
-
- ///
- /// 获取指定层级的UI实例
- ///
- public IUiPageBehavior? GetFromLayer(string uiKey, UiLayer layer)
- {
- return _layers.TryGetValue(layer, out var layerDict) &&
- layerDict.TryGetValue(uiKey, out var page)
- ? page
- : null;
- }
-
- ///
- /// 判断指定层级是否有UI显示
- ///
- public bool HasVisibleInLayer(string uiKey, UiLayer layer)
- {
- if (!_layers.TryGetValue(layer, out var layerDict) ||
- !layerDict.TryGetValue(uiKey, out var page))
- return false;
-
- return page.IsVisible;
- }
-
- #endregion
-
- #region 路由守卫
-
- ///
- /// 注册路由守卫
- ///
- public void AddGuard(IUiRouteGuard guard)
- {
- ArgumentNullException.ThrowIfNull(guard);
-
- if (_guards.Contains(guard))
- {
- Log.Debug("Guard already registered: {0}", guard.GetType().Name);
- return;
- }
-
- _guards.Add(guard);
- // 按优先级排序
- _guards.Sort((a, b) => a.Priority.CompareTo(b.Priority));
- Log.Debug("Guard registered: {0}, Priority={1}", guard.GetType().Name, guard.Priority);
- }
-
- ///
- /// 注册路由守卫(泛型方法)
- ///
- public void AddGuard() where T : IUiRouteGuard, new()
- {
- var guard = new T();
- AddGuard(guard);
- }
-
- ///
- /// 移除路由守卫
- ///
- public void RemoveGuard(IUiRouteGuard guard)
- {
- ArgumentNullException.ThrowIfNull(guard);
-
- if (_guards.Remove(guard)) Log.Debug("Guard removed: {0}", guard.GetType().Name);
- }
-
- ///
- /// 执行进入守卫
- ///
private async Task ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param)
{
foreach (var guard in _guards)
+ {
try
{
Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, uiKey);
@@ -684,18 +610,18 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
catch (Exception ex)
{
Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message);
- if (guard.CanInterrupt) return false;
+ if (guard.CanInterrupt)
+ return false;
}
+ }
return true;
}
- ///
- /// 执行离开守卫
- ///
private async Task ExecuteLeaveGuardsAsync(string uiKey)
{
foreach (var guard in _guards)
+ {
try
{
Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, uiKey);
@@ -707,15 +633,19 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
return false;
}
- if (!guard.CanInterrupt) continue;
- Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name);
- return true;
+ if (guard.CanInterrupt)
+ {
+ Log.Debug("Leave guard {0} passed, can interrupt = true", guard.GetType().Name);
+ return true;
+ }
}
catch (Exception ex)
{
Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message);
- if (guard.CanInterrupt) return false;
+ if (guard.CanInterrupt)
+ return false;
}
+ }
return true;
}