using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; namespace AlicizaX.UI { public abstract class ViewProvider { private readonly List viewHolders = new(); private readonly Dictionary viewHoldersByIndex = new(); private readonly Dictionary> viewHoldersByDataIndex = new(); private readonly Dictionary viewHolderPositions = new(); public IAdapter Adapter { get; set; } public LayoutManager LayoutManager { get; set; } public IReadOnlyList 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 holders) && holders is { Count: > 0 } ? holders[0] : null; } public bool TryGetViewHoldersByDataIndex(int dataIndex, out IReadOnlyList holders) { if (viewHoldersByDataIndex.TryGetValue(dataIndex, out List 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 holders)) { holders = new List(); 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 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); } } } }