2025-03-12 20:59:12 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
2026-03-31 15:18:50 +08:00
|
|
|
using UnityEngine.EventSystems;
|
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
|
|
|
{
|
2025-12-26 14:22:46 +08:00
|
|
|
public abstract class ViewProvider
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
private ViewHolder[] visibleHolders = new ViewHolder[8];
|
|
|
|
|
private ViewHolder[] removeBuffer = new ViewHolder[4];
|
|
|
|
|
private ViewHolderBucket[] bucketPool = new ViewHolderBucket[8];
|
|
|
|
|
private int visibleHead;
|
|
|
|
|
private int visibleCount;
|
|
|
|
|
private int bucketPoolCount;
|
2026-03-31 15:18:50 +08:00
|
|
|
private readonly Dictionary<int, ViewHolder> viewHoldersByIndex = new();
|
2026-04-29 14:44:30 +08:00
|
|
|
private readonly Dictionary<int, ViewHolderBucket> viewHoldersByDataIndex = new();
|
2026-03-31 15:18:50 +08:00
|
|
|
private readonly Dictionary<int, int> viewHolderPositions = new();
|
2025-03-12 20:59:12 +08:00
|
|
|
|
|
|
|
|
public IAdapter Adapter { get; set; }
|
2026-03-11 14:18:07 +08:00
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
public LayoutManager LayoutManager { get; set; }
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
public int VisibleCount => visibleCount;
|
|
|
|
|
|
|
|
|
|
public ViewHolder GetVisibleViewHolder(int index)
|
|
|
|
|
{
|
|
|
|
|
return index >= 0 && index < visibleCount ? visibleHolders[GetVisibleSlot(index)] : null;
|
|
|
|
|
}
|
2026-03-31 15:18:50 +08:00
|
|
|
|
|
|
|
|
public abstract string PoolStats { get; }
|
2025-03-12 20:59:12 +08:00
|
|
|
|
|
|
|
|
protected RecyclerView recyclerView;
|
|
|
|
|
protected ViewHolder[] templates;
|
|
|
|
|
|
|
|
|
|
public ViewProvider(RecyclerView recyclerView, ViewHolder[] templates)
|
|
|
|
|
{
|
|
|
|
|
this.recyclerView = recyclerView;
|
|
|
|
|
this.templates = templates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract ViewHolder GetTemplate(string viewName);
|
|
|
|
|
|
|
|
|
|
public abstract ViewHolder Allocate(string viewName);
|
|
|
|
|
|
|
|
|
|
public abstract void Free(string viewName, ViewHolder viewHolder);
|
|
|
|
|
|
|
|
|
|
public abstract void Reset();
|
|
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public abstract void PreparePool();
|
|
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
public void CreateViewHolder(int index)
|
|
|
|
|
{
|
|
|
|
|
for (int i = index; i < index + LayoutManager.Unit; i++)
|
|
|
|
|
{
|
|
|
|
|
if (i > Adapter.GetItemCount() - 1) break;
|
|
|
|
|
|
|
|
|
|
string viewName = Adapter.GetViewName(i);
|
|
|
|
|
var viewHolder = Allocate(viewName);
|
|
|
|
|
viewHolder.Name = viewName;
|
|
|
|
|
viewHolder.Index = i;
|
2026-03-31 15:18:50 +08:00
|
|
|
viewHolder.DataIndex = i;
|
|
|
|
|
viewHolder.RecyclerView = recyclerView;
|
2026-04-29 14:44:30 +08:00
|
|
|
(Adapter as IItemRenderPrewarmer)?.PrewarmItemRender(viewHolder, viewName);
|
|
|
|
|
if (!AddVisibleHolder(viewHolder))
|
|
|
|
|
{
|
|
|
|
|
Free(viewName, viewHolder);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!RegisterViewHolder(viewHolder))
|
|
|
|
|
{
|
|
|
|
|
RemoveVisibleHolder(viewHolder);
|
|
|
|
|
Free(viewName, viewHolder);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-12-26 14:22:46 +08:00
|
|
|
|
2025-03-12 20:59:12 +08:00
|
|
|
LayoutManager.Layout(viewHolder, i);
|
|
|
|
|
Adapter.OnBindViewHolder(viewHolder, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RemoveViewHolder(int index)
|
|
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
int removeCount = 0;
|
|
|
|
|
int end = index + LayoutManager.Unit;
|
|
|
|
|
EnsureRemoveBufferCapacity(LayoutManager.Unit);
|
|
|
|
|
for (int i = index; i < end; i++)
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
if (i > Adapter.GetItemCount() - 1)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-03-12 20:59:12 +08:00
|
|
|
|
|
|
|
|
int viewHolderIndex = GetViewHolderIndex(i);
|
2026-04-29 14:44:30 +08:00
|
|
|
if (viewHolderIndex < 0 || viewHolderIndex >= visibleCount)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-03-12 20:59:12 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
removeBuffer[removeCount++] = visibleHolders[GetVisibleSlot(viewHolderIndex)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < removeCount; i++)
|
|
|
|
|
{
|
|
|
|
|
ViewHolder viewHolder = removeBuffer[i];
|
|
|
|
|
removeBuffer[i] = null;
|
|
|
|
|
if (viewHolder == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-03-12 20:59:12 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
string viewName = viewHolder.Name;
|
2026-04-29 14:44:30 +08:00
|
|
|
RemoveVisibleHolder(viewHolder);
|
2026-03-31 15:18:50 +08:00
|
|
|
UnregisterViewHolder(viewHolder);
|
2026-03-27 18:38:29 +08:00
|
|
|
Adapter?.OnRecycleViewHolder(viewHolder);
|
2025-05-30 13:43:08 +08:00
|
|
|
viewHolder.OnRecycled();
|
2026-03-31 15:18:50 +08:00
|
|
|
ClearSelectedState(viewHolder);
|
|
|
|
|
Free(viewName, viewHolder);
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ViewHolder GetViewHolder(int index)
|
|
|
|
|
{
|
2026-03-31 15:18:50 +08:00
|
|
|
return viewHoldersByIndex.TryGetValue(index, out ViewHolder viewHolder)
|
|
|
|
|
? viewHolder
|
|
|
|
|
: null;
|
|
|
|
|
}
|
2025-04-01 15:21:02 +08:00
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
public ViewHolder GetViewHolderByDataIndex(int dataIndex)
|
|
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
return viewHoldersByDataIndex.TryGetValue(dataIndex, out ViewHolderBucket bucket) && bucket.Count > 0
|
|
|
|
|
? bucket[0]
|
2026-03-31 15:18:50 +08:00
|
|
|
: null;
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
public bool TryGetViewHolderBucket(int dataIndex, out ViewHolderBucket bucket)
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
return viewHoldersByDataIndex.TryGetValue(dataIndex, out bucket) && bucket.Count > 0;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetViewHolderIndex(int index)
|
|
|
|
|
{
|
|
|
|
|
return viewHolderPositions.TryGetValue(index, out int viewHolderIndex)
|
|
|
|
|
? viewHolderIndex
|
|
|
|
|
: -1;
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
for (int i = 0; i < visibleCount; i++)
|
2025-03-12 20:59:12 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
ViewHolder viewHolder = visibleHolders[GetVisibleSlot(i)];
|
|
|
|
|
if (viewHolder == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
string viewName = viewHolder.Name;
|
2026-03-27 18:38:29 +08:00
|
|
|
Adapter?.OnRecycleViewHolder(viewHolder);
|
2026-03-31 15:18:50 +08:00
|
|
|
UnregisterViewHolder(viewHolder);
|
2026-03-27 18:38:29 +08:00
|
|
|
viewHolder.OnRecycled();
|
2026-03-31 15:18:50 +08:00
|
|
|
ClearSelectedState(viewHolder);
|
|
|
|
|
Free(viewName, viewHolder);
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
2025-04-01 15:21:02 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
System.Array.Clear(visibleHolders, 0, visibleHolders.Length);
|
|
|
|
|
visibleHead = 0;
|
|
|
|
|
visibleCount = 0;
|
2026-03-31 15:18:50 +08:00
|
|
|
viewHoldersByIndex.Clear();
|
2026-04-29 14:44:30 +08:00
|
|
|
foreach (var pair in viewHoldersByDataIndex)
|
|
|
|
|
{
|
|
|
|
|
ReleaseBucket(pair.Value);
|
|
|
|
|
}
|
2026-03-31 15:18:50 +08:00
|
|
|
viewHoldersByDataIndex.Clear();
|
|
|
|
|
viewHolderPositions.Clear();
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Vector2 CalculateViewSize(int index)
|
|
|
|
|
{
|
|
|
|
|
Vector2 size = GetTemplate(Adapter.GetViewName(index)).SizeDelta;
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int GetItemCount()
|
|
|
|
|
{
|
|
|
|
|
return Adapter == null ? 0 : Adapter.GetItemCount();
|
|
|
|
|
}
|
2026-03-31 15:18:50 +08:00
|
|
|
|
|
|
|
|
protected int GetRecommendedWarmCount()
|
|
|
|
|
{
|
|
|
|
|
if (Adapter == null || LayoutManager == null)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int itemCount = Adapter.GetItemCount();
|
|
|
|
|
if (itemCount <= 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int start = Mathf.Max(0, LayoutManager.GetStartIndex());
|
|
|
|
|
int end = Mathf.Max(start, LayoutManager.GetEndIndex());
|
|
|
|
|
int visibleCount = end - start + 1;
|
2026-04-29 14:44:30 +08:00
|
|
|
int unit = Mathf.Max(1, LayoutManager.Unit);
|
|
|
|
|
int bufferCount = unit * 2;
|
2026-03-31 15:18:50 +08:00
|
|
|
return Mathf.Min(itemCount, visibleCount + bufferCount);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
protected void PrepareVisibleStorage(int warmCount)
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
int capacity = Mathf.Max(Mathf.Max(1, LayoutManager != null ? LayoutManager.Unit : 1), warmCount);
|
|
|
|
|
if (visibleHolders.Length < capacity)
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
visibleHolders = new ViewHolder[capacity];
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
if (removeBuffer.Length < capacity)
|
|
|
|
|
{
|
|
|
|
|
removeBuffer = new ViewHolder[capacity];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool RegisterViewHolder(ViewHolder viewHolder)
|
|
|
|
|
{
|
|
|
|
|
if (viewHolder == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-03-31 15:18:50 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
if (!viewHoldersByDataIndex.TryGetValue(viewHolder.DataIndex, out ViewHolderBucket bucket))
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
bucket = AllocateBucket();
|
|
|
|
|
if (bucket == null)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewHoldersByDataIndex[viewHolder.DataIndex] = bucket;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
viewHoldersByIndex[viewHolder.Index] = viewHolder;
|
|
|
|
|
viewHolderPositions[viewHolder.Index] = GetVisibleSlot(visibleCount - 1);
|
|
|
|
|
bucket.Add(viewHolder);
|
|
|
|
|
return true;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UnregisterViewHolder(ViewHolder viewHolder)
|
|
|
|
|
{
|
|
|
|
|
if (viewHolder == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewHoldersByIndex.Remove(viewHolder.Index);
|
|
|
|
|
viewHolderPositions.Remove(viewHolder.Index);
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
if (!viewHoldersByDataIndex.TryGetValue(viewHolder.DataIndex, out ViewHolderBucket bucket))
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
bucket.Remove(viewHolder);
|
|
|
|
|
if (bucket.Count == 0)
|
2026-04-15 14:51:57 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
viewHoldersByDataIndex.Remove(viewHolder.DataIndex);
|
|
|
|
|
ReleaseBucket(bucket);
|
2026-04-15 14:51:57 +08:00
|
|
|
}
|
2026-04-29 14:44:30 +08:00
|
|
|
}
|
2026-04-15 14:51:57 +08:00
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
private bool AddVisibleHolder(ViewHolder viewHolder)
|
|
|
|
|
{
|
|
|
|
|
if (visibleCount == visibleHolders.Length)
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
|
|
|
UnityEngine.Debug.LogError("RecyclerView visible holder capacity exceeded. Increase warm count.");
|
|
|
|
|
#endif
|
|
|
|
|
return false;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
2026-04-29 14:44:30 +08:00
|
|
|
|
|
|
|
|
visibleHolders[GetVisibleSlot(visibleCount)] = viewHolder;
|
|
|
|
|
visibleCount++;
|
|
|
|
|
return true;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
private void RemoveVisibleHolder(ViewHolder viewHolder)
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
if (!viewHolderPositions.TryGetValue(viewHolder.Index, out int slot))
|
2026-03-31 15:18:50 +08:00
|
|
|
{
|
2026-04-29 14:44:30 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int last = GetVisibleSlot(visibleCount - 1);
|
|
|
|
|
ViewHolder lastHolder = visibleHolders[last];
|
|
|
|
|
visibleHolders[slot] = lastHolder;
|
|
|
|
|
visibleHolders[last] = null;
|
|
|
|
|
visibleCount--;
|
|
|
|
|
if (visibleCount == 0)
|
|
|
|
|
{
|
|
|
|
|
visibleHead = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lastHolder != null && lastHolder != viewHolder)
|
|
|
|
|
{
|
|
|
|
|
viewHolderPositions[lastHolder.Index] = slot;
|
2026-03-31 15:18:50 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-29 14:44:30 +08:00
|
|
|
private int GetVisibleSlot(int index)
|
|
|
|
|
{
|
|
|
|
|
return (visibleHead + index) % visibleHolders.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureRemoveBufferCapacity(int required)
|
|
|
|
|
{
|
|
|
|
|
if (required <= removeBuffer.Length)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
|
|
|
UnityEngine.Debug.LogError("RecyclerView remove buffer capacity exceeded. Increase warm count.");
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-31 15:18:50 +08:00
|
|
|
private static void ClearSelectedState(ViewHolder viewHolder)
|
|
|
|
|
{
|
|
|
|
|
if (viewHolder == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventSystem eventSystem = EventSystem.current;
|
|
|
|
|
if (eventSystem == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GameObject selected = eventSystem.currentSelectedGameObject;
|
|
|
|
|
if (selected != null && selected.transform.IsChildOf(viewHolder.transform))
|
|
|
|
|
{
|
|
|
|
|
eventSystem.SetSelectedGameObject(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-29 14:44:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void PrepareBucketPool(int count)
|
|
|
|
|
{
|
|
|
|
|
PrepareVisibleStorage(count);
|
|
|
|
|
EnsureBucketPoolCapacity(count);
|
|
|
|
|
int capacity = GetBucketCapacity();
|
|
|
|
|
while (bucketPoolCount < count)
|
|
|
|
|
{
|
|
|
|
|
bucketPool[bucketPoolCount++] = new ViewHolderBucket(capacity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ViewHolderBucket AllocateBucket()
|
|
|
|
|
{
|
|
|
|
|
if (bucketPoolCount > 0)
|
|
|
|
|
{
|
|
|
|
|
ViewHolderBucket bucket = bucketPool[--bucketPoolCount];
|
|
|
|
|
bucketPool[bucketPoolCount] = null;
|
|
|
|
|
bucket.Clear();
|
|
|
|
|
return bucket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
|
|
|
UnityEngine.Debug.LogError("ViewHolderBucket pool is empty. Increase RecyclerView warm count.");
|
|
|
|
|
#endif
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReleaseBucket(ViewHolderBucket bucket)
|
|
|
|
|
{
|
|
|
|
|
if (bucket == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bucket.Clear();
|
|
|
|
|
EnsureBucketPoolCapacity(bucketPoolCount + 1);
|
|
|
|
|
bucketPool[bucketPoolCount++] = bucket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int GetBucketCapacity()
|
|
|
|
|
{
|
|
|
|
|
return Mathf.Max(4, LayoutManager != null ? LayoutManager.Unit + 1 : 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureBucketPoolCapacity(int required)
|
|
|
|
|
{
|
|
|
|
|
if (required <= bucketPool.Length)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int capacity = bucketPool.Length;
|
|
|
|
|
while (capacity < required)
|
|
|
|
|
{
|
|
|
|
|
capacity <<= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ViewHolderBucket[] next = new ViewHolderBucket[capacity];
|
|
|
|
|
System.Array.Copy(bucketPool, next, bucketPoolCount);
|
|
|
|
|
bucketPool = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public sealed class ViewHolderBucket
|
|
|
|
|
{
|
|
|
|
|
private readonly ViewHolder[] holders;
|
|
|
|
|
|
|
|
|
|
public ViewHolderBucket(int capacity)
|
|
|
|
|
{
|
|
|
|
|
holders = new ViewHolder[capacity];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int Count { get; private set; }
|
|
|
|
|
|
|
|
|
|
public ViewHolder this[int index]
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (index < 0 || index >= Count)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return holders[index];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Add(ViewHolder holder)
|
|
|
|
|
{
|
|
|
|
|
if (Count == holders.Length)
|
|
|
|
|
{
|
|
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
|
|
|
UnityEngine.Debug.LogError("ViewHolderBucket capacity exceeded.");
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
holders[Count++] = holder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Remove(ViewHolder holder)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (holders[i] != holder)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Count--;
|
|
|
|
|
holders[i] = holders[Count];
|
|
|
|
|
holders[Count] = null;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
|
|
|
|
holders[i] = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-12 20:59:12 +08:00
|
|
|
}
|
|
|
|
|
}
|