com.alicizax.unity.ui.exten.../Runtime/RecyclerView/ViewProvider/ViewProvider.cs
陈思海 dc8c840d69 RecyclerView 大优化
优化RecycleView 渲染架构
优化RecyclerView 渲染性能 增加 缓存 异步
增加Navagation导航锚点相关
2026-03-31 15:18:50 +08:00

242 lines
7.5 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace AlicizaX.UI
{
public abstract class ViewProvider
{
private readonly List<ViewHolder> viewHolders = new();
private readonly Dictionary<int, ViewHolder> viewHoldersByIndex = new();
private readonly Dictionary<int, List<ViewHolder>> viewHoldersByDataIndex = new();
private readonly Dictionary<int, int> viewHolderPositions = new();
public IAdapter Adapter { get; set; }
public LayoutManager LayoutManager { get; set; }
public IReadOnlyList<ViewHolder> ViewHolders => viewHolders;
public abstract string PoolStats { get; }
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[] GetTemplates();
public abstract ViewHolder Allocate(string viewName);
public abstract void Free(string viewName, ViewHolder viewHolder);
public abstract void Reset();
public abstract void PreparePool();
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;
viewHolder.DataIndex = i;
viewHolder.RecyclerView = recyclerView;
viewHolders.Add(viewHolder);
RegisterViewHolder(viewHolder);
LayoutManager.Layout(viewHolder, i);
Adapter.OnBindViewHolder(viewHolder, i);
}
}
public void RemoveViewHolder(int index)
{
for (int i = index; i < index + LayoutManager.Unit; i++)
{
if (i > Adapter.GetItemCount() - 1) break;
int viewHolderIndex = GetViewHolderIndex(i);
if (viewHolderIndex < 0 || viewHolderIndex >= viewHolders.Count) return;
var viewHolder = viewHolders[viewHolderIndex];
string viewName = viewHolder.Name;
viewHolders.RemoveAt(viewHolderIndex);
UnregisterViewHolder(viewHolder);
RebuildViewHolderPositions(viewHolderIndex);
Adapter?.OnRecycleViewHolder(viewHolder);
viewHolder.OnRecycled();
ClearSelectedState(viewHolder);
Free(viewName, viewHolder);
}
}
public ViewHolder GetViewHolder(int index)
{
return viewHoldersByIndex.TryGetValue(index, out ViewHolder viewHolder)
? viewHolder
: null;
}
public ViewHolder GetViewHolderByDataIndex(int dataIndex)
{
return viewHoldersByDataIndex.TryGetValue(dataIndex, out List<ViewHolder> holders) &&
holders is { Count: > 0 }
? holders[0]
: null;
}
public bool TryGetViewHoldersByDataIndex(int dataIndex, out IReadOnlyList<ViewHolder> holders)
{
if (viewHoldersByDataIndex.TryGetValue(dataIndex, out List<ViewHolder> list) && list.Count > 0)
{
holders = list;
return true;
}
holders = null;
return false;
}
public int GetViewHolderIndex(int index)
{
return viewHolderPositions.TryGetValue(index, out int viewHolderIndex)
? viewHolderIndex
: -1;
}
public void Clear()
{
foreach (var viewHolder in viewHolders)
{
string viewName = viewHolder.Name;
Adapter?.OnRecycleViewHolder(viewHolder);
UnregisterViewHolder(viewHolder);
viewHolder.OnRecycled();
ClearSelectedState(viewHolder);
Free(viewName, viewHolder);
}
viewHolders.Clear();
viewHoldersByIndex.Clear();
viewHoldersByDataIndex.Clear();
viewHolderPositions.Clear();
}
public Vector2 CalculateViewSize(int index)
{
Vector2 size = GetTemplate(Adapter.GetViewName(index)).SizeDelta;
return size;
}
public int GetItemCount()
{
return Adapter == null ? 0 : Adapter.GetItemCount();
}
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;
int bufferCount = Mathf.Max(1, LayoutManager.Unit);
return Mathf.Min(itemCount, visibleCount + bufferCount);
}
private void RegisterViewHolder(ViewHolder viewHolder)
{
if (viewHolder == null)
{
return;
}
viewHoldersByIndex[viewHolder.Index] = viewHolder;
viewHolderPositions[viewHolder.Index] = viewHolders.Count - 1;
if (!viewHoldersByDataIndex.TryGetValue(viewHolder.DataIndex, out List<ViewHolder> holders))
{
holders = new List<ViewHolder>();
viewHoldersByDataIndex[viewHolder.DataIndex] = holders;
}
holders.Add(viewHolder);
}
private void UnregisterViewHolder(ViewHolder viewHolder)
{
if (viewHolder == null)
{
return;
}
viewHoldersByIndex.Remove(viewHolder.Index);
viewHolderPositions.Remove(viewHolder.Index);
if (!viewHoldersByDataIndex.TryGetValue(viewHolder.DataIndex, out List<ViewHolder> holders))
{
return;
}
holders.Remove(viewHolder);
if (holders.Count == 0)
{
viewHoldersByDataIndex.Remove(viewHolder.DataIndex);
}
}
private void RebuildViewHolderPositions(int startIndex)
{
for (int i = startIndex; i < viewHolders.Count; i++)
{
ViewHolder holder = viewHolders[i];
if (holder != null)
{
viewHolderPositions[holder.Index] = i;
}
}
}
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);
}
}
}
}