Compare commits

..

2 Commits

Author SHA1 Message Date
6f897a7af7 优化 2026-04-15 14:23:30 +08:00
52eaadb67d Update UXHotkeyRegisterManager.cs 2026-04-15 14:15:27 +08:00
3 changed files with 87 additions and 23 deletions

View File

@ -33,10 +33,12 @@ namespace UnityEngine.UI
{ {
Holder = holder; Holder = holder;
HierarchyDepth = GetHierarchyDepth(holder.transform); HierarchyDepth = GetHierarchyDepth(holder.transform);
BlocksLowerScopes = FindParentHolder(holder) == null; ParentHolder = FindParentHolder(holder);
BlocksLowerScopes = ParentHolder == null;
} }
public readonly UIHolderObjectBase Holder; public readonly UIHolderObjectBase Holder;
public readonly UIHolderObjectBase ParentHolder;
public readonly int HierarchyDepth; public readonly int HierarchyDepth;
public readonly bool BlocksLowerScopes; public readonly bool BlocksLowerScopes;
public readonly Dictionary<string, List<HotkeyRegistration>> RegistrationsByAction = new(StringComparer.Ordinal); public readonly Dictionary<string, List<HotkeyRegistration>> RegistrationsByAction = new(StringComparer.Ordinal);
@ -424,28 +426,30 @@ namespace UnityEngine.UI
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Dispatch(string actionId, EHotkeyPressType pressType) private static void Dispatch(string actionId, EHotkeyPressType pressType)
{ {
HotkeyScope[] leafScopes = GetLeafScopes(); HotkeyScope leafScope = GetTopLeafScope();
if (leafScopes.Length == 0) if (leafScope == null)
{ {
return; return;
} }
TryDispatchToScopeChain(leafScopes[0], actionId, pressType); TryDispatchToScopeChain(leafScope, actionId, pressType);
} }
private static bool TryDispatchToScopeChain(HotkeyScope leafScope, string actionId, EHotkeyPressType pressType) private static bool TryDispatchToScopeChain(HotkeyScope leafScope, string actionId, EHotkeyPressType pressType)
{ {
UIHolderObjectBase currentHolder = leafScope.Holder; HotkeyScope current = leafScope;
while (currentHolder != null) while (current != null)
{ {
if (_scopes.TryGetValue(currentHolder, out var scope) if (TryGetLatestRegistration(current, actionId, pressType, out var registration))
&& TryGetLatestRegistration(scope, actionId, pressType, out var registration))
{ {
registration.Trigger?.HotkeyActionTrigger(); registration.Trigger?.HotkeyActionTrigger();
return true; return true;
} }
currentHolder = FindParentHolder(currentHolder); UIHolderObjectBase parentHolder = current.ParentHolder;
current = parentHolder != null && _scopes.TryGetValue(parentHolder, out var parentScope)
? parentScope
: null;
} }
return false; return false;
@ -470,7 +474,7 @@ namespace UnityEngine.UI
return false; return false;
} }
private static HotkeyScope[] GetLeafScopes() private static HotkeyScope GetTopLeafScope()
{ {
_leafScopes.Clear(); _leafScopes.Clear();
_ancestorHolders.Clear(); _ancestorHolders.Clear();
@ -486,11 +490,18 @@ namespace UnityEngine.UI
continue; continue;
} }
UIHolderObjectBase parentHolder = FindParentHolder(scope.Holder); UIHolderObjectBase parentHolder = scope.ParentHolder;
while (parentHolder != null) while (parentHolder != null)
{ {
_ancestorHolders.Add(parentHolder); _ancestorHolders.Add(parentHolder);
parentHolder = FindParentHolder(parentHolder); if (_scopes.TryGetValue(parentHolder, out var parentScope))
{
parentHolder = parentScope.ParentHolder;
}
else
{
break;
}
} }
} }
@ -506,8 +517,13 @@ namespace UnityEngine.UI
} }
} }
if (_leafScopes.Count == 0)
{
return null;
}
_leafScopes.Sort(CompareScopePriority); _leafScopes.Sort(CompareScopePriority);
return _leafScopes.ToArray(); return _leafScopes[0];
} }
private static bool IsScopeActive(HotkeyScope scope) private static bool IsScopeActive(HotkeyScope scope)

View File

@ -23,6 +23,9 @@ namespace UnityEngine.UI
private ulong _activationSerial; private ulong _activationSerial;
private bool _missingEventSystemLogged; private bool _missingEventSystemLogged;
private bool _topScopeDirty = true;
private bool _suppressionDirty = true;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Bootstrap() private static void Bootstrap()
{ {
@ -101,6 +104,8 @@ namespace UnityEngine.UI
} }
_scopes.Add(scope); _scopes.Add(scope);
_topScopeDirty = true;
_suppressionDirty = true;
} }
internal void UnregisterScope(UXNavigationScope scope) internal void UnregisterScope(UXNavigationScope scope)
@ -117,7 +122,17 @@ namespace UnityEngine.UI
scope.IsAvailable = false; scope.IsAvailable = false;
scope.SetNavigationSuppressed(false); scope.SetNavigationSuppressed(false);
_scopes.Remove(scope);
int idx = _scopes.IndexOf(scope);
if (idx >= 0)
{
int last = _scopes.Count - 1;
_scopes[idx] = _scopes[last];
_scopes.RemoveAt(last);
}
_topScopeDirty = true;
_suppressionDirty = true;
} }
internal void MarkDiscoveryDirty() internal void MarkDiscoveryDirty()
@ -138,13 +153,22 @@ namespace UnityEngine.UI
DiscoverScopes(); DiscoverScopes();
} }
if (_topScopeDirty)
{
UXNavigationScope newTopScope = FindTopScope(); UXNavigationScope newTopScope = FindTopScope();
_topScopeDirty = false;
if (!ReferenceEquals(_topScope, newTopScope)) if (!ReferenceEquals(_topScope, newTopScope))
{ {
_topScope = newTopScope; _topScope = newTopScope;
_suppressionDirty = true;
}
} }
if (_suppressionDirty)
{
ApplyScopeSuppression(); ApplyScopeSuppression();
_suppressionDirty = false;
}
if (UXInputModeService.CurrentMode == UXInputMode.Gamepad) if (UXInputModeService.CurrentMode == UXInputMode.Gamepad)
{ {
@ -237,6 +261,9 @@ namespace UnityEngine.UI
{ {
_scopes[i]?.InvalidateSelectableCache(); _scopes[i]?.InvalidateSelectableCache();
} }
_topScopeDirty = true;
_suppressionDirty = true;
} }
} }
@ -275,6 +302,8 @@ namespace UnityEngine.UI
{ {
scope.ActivationSerial = ++_activationSerial; scope.ActivationSerial = ++_activationSerial;
} }
_suppressionDirty = true;
} }
if (!available) if (!available)
@ -304,11 +333,13 @@ namespace UnityEngine.UI
return false; return false;
} }
return !IsNavigationSkipped(scope.transform) return !scope.IsNavigationSkipped
&& scope.HasAvailableSelectable() && scope.HasAvailableSelectable()
&& TryGetInteractiveLayerRoot(scope.transform, out _); && TryGetInteractiveLayerRoot(scope.transform, out _);
} }
// 保留静态方法用于 DiscoverScopes 中对 LayerRoot / Holder 节点的检测
// 这些节点无 UXNavigationScope调用频次低仅在 dirty 时),无需缓存
private static bool IsNavigationSkipped(Transform current) private static bool IsNavigationSkipped(Transform current)
{ {
return current != null && current.GetComponentInParent<UXNavigationSkip>(true) != null; return current != null && current.GetComponentInParent<UXNavigationSkip>(true) != null;

View File

@ -33,6 +33,9 @@ namespace UnityEngine.UI
private bool _navigationSuppressed; private bool _navigationSuppressed;
private int _cachedHierarchyDepth = -1; private int _cachedHierarchyDepth = -1;
private bool _cachedIsSkipped;
private bool _isSkippedCacheValid;
internal ulong ActivationSerial { get; set; } internal ulong ActivationSerial { get; set; }
internal bool IsAvailable { get; set; } internal bool IsAvailable { get; set; }
internal bool WasAvailable { get; set; } internal bool WasAvailable { get; set; }
@ -47,6 +50,19 @@ namespace UnityEngine.UI
public bool RequireSelectionWhenGamepad => _requireSelectionWhenGamepad; public bool RequireSelectionWhenGamepad => _requireSelectionWhenGamepad;
public bool BlockLowerScopes => _blockLowerScopes; public bool BlockLowerScopes => _blockLowerScopes;
internal bool IsNavigationSkipped
{
get
{
if (!_isSkippedCacheValid)
{
_cachedIsSkipped = GetComponentInParent<UXNavigationSkip>(true) != null;
_isSkippedCacheValid = true;
}
return _cachedIsSkipped;
}
}
internal Canvas Canvas internal Canvas Canvas
{ {
get get
@ -108,6 +124,7 @@ namespace UnityEngine.UI
_cachedCanvas = null; _cachedCanvas = null;
_cachedHolder = null; _cachedHolder = null;
_cachedHierarchyDepth = -1; _cachedHierarchyDepth = -1;
_isSkippedCacheValid = false;
} }
#if UNITY_EDITOR #if UNITY_EDITOR
@ -219,12 +236,12 @@ namespace UnityEngine.UI
internal void SetNavigationSuppressed(bool suppressed) internal void SetNavigationSuppressed(bool suppressed)
{ {
RefreshSelectableCache();
if (_navigationSuppressed == suppressed) if (_navigationSuppressed == suppressed)
{ {
return; return;
} }
RefreshSelectableCache();
_navigationSuppressed = suppressed; _navigationSuppressed = suppressed;
for (int i = 0; i < _cachedSelectables.Count; i++) for (int i = 0; i < _cachedSelectables.Count; i++)
{ {
@ -281,11 +298,11 @@ namespace UnityEngine.UI
} }
_removeBuffer.Clear(); _removeBuffer.Clear();
foreach (var pair in _baselineNavigation) foreach (Selectable key in _baselineNavigation.Keys)
{ {
if (!_cachedSelectableSet.Contains(pair.Key)) if (!_cachedSelectableSet.Contains(key))
{ {
_removeBuffer.Add(pair.Key); _removeBuffer.Add(key);
} }
} }