Compare commits

..

No commits in common. "6bf99f313cef580a226381b86542d1e4d5d9fef5" and "0f7d062a9fc16e61ef5fd521a56d2ee3c0c99891" have entirely different histories.

3 changed files with 46 additions and 86 deletions

View File

@ -9,16 +9,16 @@ namespace UnityEngine.UI
internal sealed class UXNavigationRuntime : MonoBehaviour internal sealed class UXNavigationRuntime : MonoBehaviour
{ {
private static UXNavigationRuntime _instance; private static UXNavigationRuntime _instance;
private static readonly string CacheLayerName = $"Layer{(int)UILayer.All}-{UILayer.All}";
private const float DiscoveryInterval = 0.5f;
private readonly HashSet<UXNavigationScope> _scopeSet = new(); private readonly HashSet<UXNavigationScope> _scopeSet = new();
private readonly List<UXNavigationScope> _scopes = new(32); private readonly List<UXNavigationScope> _scopes = new(32);
private readonly HashSet<Transform> _interactiveLayerRoots = new(); private readonly HashSet<Transform> _interactiveLayerRoots = new();
private readonly List<UIHolderObjectBase> _holderBuffer = new(32);
private Transform _uiCanvasRoot; private Transform _uiCanvasRoot;
private UXNavigationScope _topScope; private UXNavigationScope _topScope;
private GameObject _lastObservedSelection; private GameObject _lastObservedSelection;
private float _nextDiscoveryTime;
private bool _discoveryDirty = true; private bool _discoveryDirty = true;
private ulong _activationSerial; private ulong _activationSerial;
private bool _missingEventSystemLogged; private bool _missingEventSystemLogged;
@ -101,6 +101,7 @@ namespace UnityEngine.UI
} }
_scopes.Add(scope); _scopes.Add(scope);
MarkDiscoveryDirty();
} }
internal void UnregisterScope(UXNavigationScope scope) internal void UnregisterScope(UXNavigationScope scope)
@ -115,9 +116,9 @@ namespace UnityEngine.UI
_topScope = null; _topScope = null;
} }
scope.IsAvailable = false;
scope.SetNavigationSuppressed(false); scope.SetNavigationSuppressed(false);
_scopes.Remove(scope); _scopes.Remove(scope);
MarkDiscoveryDirty();
} }
internal void MarkDiscoveryDirty() internal void MarkDiscoveryDirty()
@ -133,7 +134,7 @@ namespace UnityEngine.UI
return; return;
} }
if (_discoveryDirty) if (_discoveryDirty || Time.unscaledTime >= _nextDiscoveryTime)
{ {
DiscoverScopes(); DiscoverScopes();
} }
@ -172,7 +173,6 @@ namespace UnityEngine.UI
} }
_uiCanvasRoot = uiModule.UICanvasRoot; _uiCanvasRoot = uiModule.UICanvasRoot;
EnsureWatcher(_uiCanvasRoot);
CacheInteractiveLayers(); CacheInteractiveLayers();
DiscoverScopes(); DiscoverScopes();
} }
@ -185,23 +185,28 @@ namespace UnityEngine.UI
return; return;
} }
EnsureWatcher(_uiCanvasRoot); string cacheLayerName = $"Layer{(int)UILayer.All}-{UILayer.All}";
for (int i = 0; i < _uiCanvasRoot.childCount; i++) for (int i = 0; i < _uiCanvasRoot.childCount; i++)
{ {
Transform child = _uiCanvasRoot.GetChild(i); Transform child = _uiCanvasRoot.GetChild(i);
if (child == null || child.name == CacheLayerName) if (child == null || child.name == cacheLayerName)
{ {
continue; continue;
} }
_interactiveLayerRoots.Add(child); _interactiveLayerRoots.Add(child);
EnsureWatcher(child); if (child.GetComponent<UXNavigationLayerWatcher>() == null)
{
var watcher = child.gameObject.AddComponent<UXNavigationLayerWatcher>();
watcher.Initialize(this);
}
} }
} }
private void DiscoverScopes() private void DiscoverScopes()
{ {
_discoveryDirty = false; _discoveryDirty = false;
_nextDiscoveryTime = Time.unscaledTime + DiscoveryInterval;
CacheInteractiveLayers(); CacheInteractiveLayers();
bool addedScope = false; bool addedScope = false;
@ -212,11 +217,10 @@ namespace UnityEngine.UI
continue; continue;
} }
_holderBuffer.Clear(); UIHolderObjectBase[] holders = layerRoot.GetComponentsInChildren<UIHolderObjectBase>(true);
layerRoot.GetComponentsInChildren(true, _holderBuffer); for (int i = 0; i < holders.Length; i++)
for (int i = 0; i < _holderBuffer.Count; i++)
{ {
UIHolderObjectBase holder = _holderBuffer[i]; UIHolderObjectBase holder = holders[i];
if (holder == null if (holder == null
|| holder.GetComponent<UXNavigationScope>() != null || holder.GetComponent<UXNavigationScope>() != null
|| IsNavigationSkipped(holder.transform)) || IsNavigationSkipped(holder.transform))
@ -229,8 +233,6 @@ namespace UnityEngine.UI
} }
} }
_holderBuffer.Clear();
if (addedScope) if (addedScope)
{ {
for (int i = 0; i < _scopes.Count; i++) for (int i = 0; i < _scopes.Count; i++)
@ -240,21 +242,6 @@ namespace UnityEngine.UI
} }
} }
private void EnsureWatcher(Transform target)
{
if (target == null)
{
return;
}
if (!target.TryGetComponent(out UXNavigationLayerWatcher watcher))
{
watcher = target.gameObject.AddComponent<UXNavigationLayerWatcher>();
}
watcher.Initialize(this);
}
private UXNavigationScope FindTopScope() private UXNavigationScope FindTopScope()
{ {
UXNavigationScope bestScope = null; UXNavigationScope bestScope = null;
@ -267,7 +254,6 @@ namespace UnityEngine.UI
} }
bool available = IsScopeAvailable(scope); bool available = IsScopeAvailable(scope);
scope.IsAvailable = available;
if (scope.WasAvailable != available) if (scope.WasAvailable != available)
{ {
scope.WasAvailable = available; scope.WasAvailable = available;
@ -362,7 +348,7 @@ namespace UnityEngine.UI
continue; continue;
} }
bool suppress = scope.IsAvailable bool suppress = IsScopeAvailable(scope)
&& _topScope != null && _topScope != null
&& !ReferenceEquals(scope, _topScope) && !ReferenceEquals(scope, _topScope)
&& _topScope.BlockLowerScopes && _topScope.BlockLowerScopes

View File

@ -21,20 +21,16 @@ namespace UnityEngine.UI
[SerializeField, Header("自动选中首个可用控件")] private bool _autoSelectFirstAvailable = true; [SerializeField, Header("自动选中首个可用控件")] private bool _autoSelectFirstAvailable = true;
private readonly List<Selectable> _cachedSelectables = new(16); private readonly List<Selectable> _cachedSelectables = new(16);
private readonly HashSet<Selectable> _cachedSelectableSet = new();
private readonly Dictionary<Selectable, Navigation> _baselineNavigation = new(); private readonly Dictionary<Selectable, Navigation> _baselineNavigation = new();
private readonly List<Selectable> _removeBuffer = new(8); private readonly List<Selectable> _removeBuffer = new(8);
private readonly List<Selectable> _selectableScanBuffer = new(16);
private Canvas _cachedCanvas; private Canvas _cachedCanvas;
private UIHolderObjectBase _cachedHolder; private UIHolderObjectBase _cachedHolder;
private Selectable _lastSelected; private Selectable _lastSelected;
private bool _cacheDirty = true; private bool _cacheDirty = true;
private bool _navigationSuppressed; private bool _navigationSuppressed;
private int _cachedHierarchyDepth = -1;
internal ulong ActivationSerial { get; set; } internal ulong ActivationSerial { get; set; }
internal bool IsAvailable { get; set; }
internal bool WasAvailable { get; set; } internal bool WasAvailable { get; set; }
public Selectable DefaultSelectable public Selectable DefaultSelectable
@ -102,14 +98,6 @@ namespace UnityEngine.UI
_cacheDirty = true; _cacheDirty = true;
} }
private void OnTransformParentChanged()
{
_cacheDirty = true;
_cachedCanvas = null;
_cachedHolder = null;
_cachedHierarchyDepth = -1;
}
#if UNITY_EDITOR #if UNITY_EDITOR
private void OnValidate() private void OnValidate()
{ {
@ -119,11 +107,6 @@ namespace UnityEngine.UI
internal int GetHierarchyDepth() internal int GetHierarchyDepth()
{ {
if (_cachedHierarchyDepth >= 0)
{
return _cachedHierarchyDepth;
}
int depth = 0; int depth = 0;
Transform current = transform; Transform current = transform;
while (current != null) while (current != null)
@ -132,8 +115,7 @@ namespace UnityEngine.UI
current = current.parent; current = current.parent;
} }
_cachedHierarchyDepth = depth; return depth;
return _cachedHierarchyDepth;
} }
internal bool Owns(GameObject target) internal bool Owns(GameObject target)
@ -169,7 +151,7 @@ namespace UnityEngine.UI
for (int i = 0; i < _cachedSelectables.Count; i++) for (int i = 0; i < _cachedSelectables.Count; i++)
{ {
Selectable selectable = _cachedSelectables[i]; Selectable selectable = _cachedSelectables[i];
if (IsSelectableUsable(selectable)) if (IsSelectableValid(selectable))
{ {
return selectable; return selectable;
} }
@ -189,7 +171,7 @@ namespace UnityEngine.UI
for (int i = 0; i < _cachedSelectables.Count; i++) for (int i = 0; i < _cachedSelectables.Count; i++)
{ {
if (IsSelectableUsable(_cachedSelectables[i])) if (IsSelectableValid(_cachedSelectables[i]))
{ {
return true; return true;
} }
@ -205,7 +187,12 @@ namespace UnityEngine.UI
return; return;
} }
Selectable selectable = GetSelectableFromObject(selectedObject); Selectable selectable = selectedObject.GetComponent<Selectable>();
if (selectable == null)
{
selectable = selectedObject.GetComponentInParent<Selectable>();
}
if (IsSelectableValid(selectable)) if (IsSelectableValid(selectable))
{ {
_lastSelected = selectable; _lastSelected = selectable;
@ -214,7 +201,18 @@ namespace UnityEngine.UI
internal bool IsSelectableOwnedAndValid(GameObject selectedObject) internal bool IsSelectableOwnedAndValid(GameObject selectedObject)
{ {
return IsSelectableValid(GetSelectableFromObject(selectedObject)); if (selectedObject == null || !Owns(selectedObject))
{
return false;
}
Selectable selectable = selectedObject.GetComponent<Selectable>();
if (selectable == null)
{
selectable = selectedObject.GetComponentInParent<Selectable>();
}
return IsSelectableValid(selectable);
} }
internal void SetNavigationSuppressed(bool suppressed) internal void SetNavigationSuppressed(bool suppressed)
@ -261,7 +259,6 @@ namespace UnityEngine.UI
_cacheDirty = false; _cacheDirty = false;
_cachedSelectables.Clear(); _cachedSelectables.Clear();
_cachedSelectableSet.Clear();
if (_explicitSelectables != null && _explicitSelectables.Count > 0) if (_explicitSelectables != null && _explicitSelectables.Count > 0)
{ {
@ -272,18 +269,17 @@ namespace UnityEngine.UI
} }
else else
{ {
_selectableScanBuffer.Clear(); Selectable[] selectables = GetComponentsInChildren<Selectable>(true);
GetComponentsInChildren(true, _selectableScanBuffer); for (int i = 0; i < selectables.Length; i++)
for (int i = 0; i < _selectableScanBuffer.Count; i++)
{ {
TryAddSelectable(_selectableScanBuffer[i]); TryAddSelectable(selectables[i]);
} }
} }
_removeBuffer.Clear(); _removeBuffer.Clear();
foreach (var pair in _baselineNavigation) foreach (var pair in _baselineNavigation)
{ {
if (!_cachedSelectableSet.Contains(pair.Key)) if (!_cachedSelectables.Contains(pair.Key))
{ {
_removeBuffer.Add(pair.Key); _removeBuffer.Add(pair.Key);
} }
@ -293,8 +289,6 @@ namespace UnityEngine.UI
{ {
_baselineNavigation.Remove(_removeBuffer[i]); _baselineNavigation.Remove(_removeBuffer[i]);
} }
_selectableScanBuffer.Clear();
} }
public void InvalidateSelectableCache() public void InvalidateSelectableCache()
@ -304,7 +298,7 @@ namespace UnityEngine.UI
private void TryAddSelectable(Selectable selectable) private void TryAddSelectable(Selectable selectable)
{ {
if (selectable == null || !Owns(selectable.gameObject) || !_cachedSelectableSet.Add(selectable)) if (selectable == null || !Owns(selectable.gameObject))
{ {
return; return;
} }
@ -317,28 +311,11 @@ namespace UnityEngine.UI
} }
private bool IsSelectableValid(Selectable selectable) private bool IsSelectableValid(Selectable selectable)
{
return IsSelectableUsable(selectable)
&& (_cachedSelectableSet.Contains(selectable) || Owns(selectable.gameObject));
}
private static bool IsSelectableUsable(Selectable selectable)
{ {
return selectable != null return selectable != null
&& selectable.IsActive() && selectable.IsActive()
&& selectable.IsInteractable(); && selectable.IsInteractable()
} && Owns(selectable.gameObject);
private static Selectable GetSelectableFromObject(GameObject selectedObject)
{
if (selectedObject == null)
{
return null;
}
return selectedObject.TryGetComponent(out Selectable selectable)
? selectable
: selectedObject.GetComponentInParent<Selectable>();
} }
} }
} }

View File

@ -17,8 +17,6 @@ namespace UnityEngine.UI
{ {
[SerializeField] private List<TransitionData> m_ChildTransitions = new(); [SerializeField] private List<TransitionData> m_ChildTransitions = new();
private SelectionState _state;
void StartChildColorTween(TransitionData transitionData, Color targetColor, bool instant) void StartChildColorTween(TransitionData transitionData, Color targetColor, bool instant)
{ {
if (transitionData.targetGraphic == null) if (transitionData.targetGraphic == null)
@ -70,8 +68,7 @@ namespace UnityEngine.UI
protected override void DoStateTransition(SelectionState state, bool instant) protected override void DoStateTransition(SelectionState state, bool instant)
{ {
base.DoStateTransition(state, instant); base.DoStateTransition(state, instant);
if (_state == state) return;
_state = state;
for (int i = 0; i < m_ChildTransitions.Count; i++) for (int i = 0; i < m_ChildTransitions.Count; i++)
{ {
TransitionData transitionData = m_ChildTransitions[i]; TransitionData transitionData = m_ChildTransitions[i];