2026-04-29 14:44:30 +08:00
|
|
|
using System.Collections.Generic;
|
2025-03-12 20:59:12 +08:00
|
|
|
using UnityEngine;
|
2026-04-29 14:44:30 +08:00
|
|
|
using UnityEngine.EventSystems;
|
|
|
|
|
using UnityEngine.UI;
|
2025-03-12 20:59:12 +08:00
|
|
|
|
2025-11-20 15:40:38 +08:00
|
|
|
namespace AlicizaX.UI
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
public abstract partial class ViewHolder : MonoBehaviour
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
|
|
|
|
private RectTransform rectTransform;
|
2026-04-29 14:44:30 +08:00
|
|
|
private Selectable focusAnchor;
|
|
|
|
|
private readonly List<Selectable> selectableCache = new();
|
|
|
|
|
private bool interactionCacheReady;
|
2026-03-27 18:38:29 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
internal IItemRender CachedItemRender;
|
|
|
|
|
internal string CachedItemRenderViewName;
|
2025-03-28 13:34:33 +08:00
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
public RectTransform RectTransform
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (rectTransform == null)
|
|
|
|
|
{
|
|
|
|
|
rectTransform = GetComponent<RectTransform>();
|
|
|
|
|
}
|
2025-03-28 13:34:33 +08:00
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
return rectTransform;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-30 13:43:08 +08:00
|
|
|
public string Name { get; internal set; }
|
2026-03-11 14:18:07 +08:00
|
|
|
|
2025-05-30 13:43:08 +08:00
|
|
|
public int Index { get; internal set; }
|
2025-03-12 20:59:12 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public int DataIndex { get; internal set; } = -1;
|
2026-03-27 18:38:29 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public RecyclerView RecyclerView { get; internal set; }
|
2025-05-30 13:43:08 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public uint BindingVersion { get; private set; }
|
2026-03-30 16:00:20 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public Vector2 SizeDelta => RectTransform.sizeDelta;
|
2025-03-12 20:59:12 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
internal uint AdvanceBindingVersion()
|
2026-03-27 18:38:29 +08:00
|
|
|
{
|
2026-03-31 15:18:50 +08:00
|
|
|
BindingVersion = BindingVersion == uint.MaxValue ? 1u : BindingVersion + 1u;
|
|
|
|
|
return BindingVersion;
|
2026-03-27 18:38:29 +08:00
|
|
|
}
|
2026-03-27 14:38:26 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
internal void RefreshInteractionCache()
|
|
|
|
|
{
|
|
|
|
|
if (interactionCacheReady)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
focusAnchor = GetComponent<Selectable>();
|
|
|
|
|
selectableCache.Clear();
|
|
|
|
|
GetComponentsInChildren(true, selectableCache);
|
|
|
|
|
interactionCacheReady = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal bool TryGetFocusTarget(out GameObject target)
|
|
|
|
|
{
|
|
|
|
|
if (TryGetInteractionFocusTarget(out target))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Selectable selectable = IsSelectableFocusable(focusAnchor) ? focusAnchor : null;
|
|
|
|
|
if (selectable == null)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < selectableCache.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (IsSelectableFocusable(selectableCache[i]))
|
|
|
|
|
{
|
|
|
|
|
selectable = selectableCache[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (selectable != null)
|
|
|
|
|
{
|
|
|
|
|
target = selectable.gameObject;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ExecuteEvents.CanHandleEvent<IMoveHandler>(gameObject) ||
|
|
|
|
|
ExecuteEvents.CanHandleEvent<ISelectHandler>(gameObject) ||
|
|
|
|
|
ExecuteEvents.CanHandleEvent<ISubmitHandler>(gameObject))
|
|
|
|
|
{
|
|
|
|
|
target = gameObject;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
protected internal virtual void OnRecycled()
|
2025-03-28 13:34:33 +08:00
|
|
|
{
|
2026-03-31 15:18:50 +08:00
|
|
|
AdvanceBindingVersion();
|
|
|
|
|
Name = string.Empty;
|
|
|
|
|
Index = -1;
|
|
|
|
|
DataIndex = -1;
|
|
|
|
|
RecyclerView = null;
|
2025-03-28 13:34:33 +08:00
|
|
|
}
|
2025-04-01 15:21:02 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
private static bool IsSelectableFocusable(Selectable selectable)
|
2025-04-02 14:53:08 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
return selectable != null &&
|
|
|
|
|
selectable.IsActive() &&
|
|
|
|
|
selectable.IsInteractable();
|
2025-04-02 14:53:08 +08:00
|
|
|
}
|
2026-04-29 14:44:30 +08:00
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
}
|