1. 使用缓存池的好处
- 不用频繁创建UI,重用不在视口内的UI(已经创建好的)
- 看下图,UI已经到了两万多个,可是创建的预制体也就20几个
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d17a93d539134167a496f0ceef80de79.png)
直接看代码吧,希望对您的工作学习有所帮助~
2. CustomInfiniteScrollView.cs
using System.Collections.Generic;
using UnityEngine;
namespace DF.Demo
{
public interface IItemBase<T>
{
void InitItem(T info);
}
public enum EScrollDirection
{
Horizontal,
Vertical,
}
public class CustomInfiniteScrollView<T, K> where K : MonoBehaviour, IItemBase<T>
{
private RectTransform content;
private Vector2 viewPortSize;
private Vector2Int rowColumn;
private Vector2Int padding;
private EScrollDirection direction;
float rowOrColumn = 0;
private Vector2 itemSize;
private string itemResPath;
private BagItem bagItem;
private List<T> items;
public Dictionary<int, GameObject> nowShowItems = new Dictionary<int, GameObject>();
private int oldMinIndex;
private int oldMaxIndex;
public void InitScrollView(RectTransform con,
Vector2 viewPortSize,
Vector2Int rowColumn,
Vector2Int padding,
EScrollDirection direction = EScrollDirection.Vertical)
{
content = con;
this.viewPortSize = viewPortSize;
this.rowColumn = rowColumn;
this.padding = padding;
this.direction = direction;
switch (direction)
{
case EScrollDirection.Horizontal:
this.rowOrColumn = rowColumn.x;
break;
case EScrollDirection.Vertical:
this.rowOrColumn = rowColumn.y;
break;
default:
break;
}
}
public void InitItemInfo(Vector2 itemSize, string itemResP, BagItem bagI)
{
this.itemSize = itemSize;
itemResPath = itemResP;
bagItem = bagI;
}
public void InitItemData(List<T> items)
{
this.items = items;
content.sizeDelta = new Vector2(0, Mathf.CeilToInt(items.Count / rowOrColumn) * (itemSize.y + padding.y));
}
public void CheckShowOrHideItemAsync()
{
int minIndex = 0;
int maxIndex = 0;
switch (direction)
{
case EScrollDirection.Horizontal:
minIndex = (int)(content.anchoredPosition.x / (itemSize.x + padding.x) * rowColumn.x);
maxIndex = (int)((content.anchoredPosition.x + viewPortSize.x) / (itemSize.x + padding.x) * rowColumn.x + rowColumn.x - 1);
break;
case EScrollDirection.Vertical:
minIndex = (int)(content.anchoredPosition.y / (itemSize.y + padding.y) * rowColumn.y);
maxIndex = Mathf.CeilToInt((content.anchoredPosition.y + viewPortSize.y) / (itemSize.y + padding.y)) * rowColumn.y + rowColumn.y - 1;
break;
default:
break;
}
if (minIndex < 0)
minIndex = 0;
if (maxIndex >= items.Count)
maxIndex = items.Count - 1;
if (minIndex != oldMinIndex || maxIndex != oldMaxIndex)
{
for (int i = oldMinIndex; i < minIndex; ++i)
{
if (nowShowItems.ContainsKey(i))
{
if (nowShowItems[i] != null)
{
UICommonItemPool<K>.Instance.Push(nowShowItems[i].GetComponent<K>());
}
nowShowItems.Remove(i);
}
}
for (int i = maxIndex + 1; i <= oldMaxIndex; ++i)
{
if (nowShowItems.ContainsKey(i))
{
if (nowShowItems[i] != null)
{
UICommonItemPool<K>.Instance.Push(nowShowItems[i].GetComponent<K>());
}
nowShowItems.Remove(i);
}
}
}
oldMinIndex = minIndex;
oldMaxIndex = maxIndex;
for (int i = minIndex; i <= maxIndex; ++i)
{
if (nowShowItems.ContainsKey(i))
{
continue;
}
else
{
int index = i;
nowShowItems.Add(index, null);
GameObject obj = null;
obj = UICommonItemPool<K>.Instance.Get().gameObject;
if (obj != null)
{
obj.transform.SetParent(content);
obj.transform.localScale = Vector3.one;
obj.transform.localPosition = new Vector3((index % rowOrColumn) * (itemSize.x + padding.x), -Mathf.FloorToInt(index / rowOrColumn) * (itemSize.x + padding.y), 0);
obj.transform.GetComponent<K>().InitItem(items[index]);
}
else
{
Debug.LogError("Obj is null");
}
if (nowShowItems.ContainsKey(index))
{
nowShowItems[index] = obj;
}
else
{
UICommonItemPool<K>.Instance.Push(nowShowItems[i].GetComponent<K>());
}
}
}
}
}
}
3. BagItem.cs
using UnityEngine;
using UnityEngine.UI;
namespace DF.Demo
{
public class BagItem : MonoBehaviour, IItemBase<Item>
{
private int id;
[SerializeField] Text text;
public void InitItem(Item info)
{
id = info.id;
text.text = info.num.ToString();
}
}
}
4. UICommonItemPool.cs
using System.Collections.Generic;
using UnityEngine;
namespace DF.Demo
{
public class UICommonItemPool<T> where T : MonoBehaviour
{
private GameObject itemRes;
public List<T> m_freeItems = new List<T>();
public List<T> m_usingItems = new List<T>();
private static UICommonItemPool<T> _instance = null;
public static UICommonItemPool<T> Instance
{
get
{
if (_instance == null) _instance = new UICommonItemPool<T>();
return _instance;
}
}
public GameObject ItemRes { set => itemRes = value; }
public T Get()
{
if (m_freeItems.Count == 0)
{
var p = GameObject.Instantiate(itemRes);
m_freeItems.Add(p.GetComponent<T>());
}
var item = m_freeItems[0];
item.gameObject.SetActive(true);
m_usingItems.Add(item);
m_freeItems.Remove(item);
return item;
}
public void Push(T item)
{
item.gameObject.SetActive(false);
m_usingItems.Remove(item);
m_freeItems.Add(item);
}
public void Clear()
{
for (int i = m_freeItems.Count - 1; i >= 0; i--)
{
var item = m_freeItems[i];
GameObject.Destroy(item.gameObject);
}
for (int i = m_usingItems.Count - 1; i >= 0; i--)
{
var item = m_usingItems[i];
GameObject.Destroy(item.gameObject);
}
m_freeItems.Clear();
m_usingItems.Clear();
}
}
}
5. TestCustomSV
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace DF.Demo
{
public class Item
{
public int id;
public int num;
}
public class TestCustomSV : MonoBehaviour
{
[SerializeField] ScrollRect scrolRect;
[SerializeField] RectTransform content;
[SerializeField] BagItem bagItem;
[SerializeField] Button showCacheStackCountBtn;
CustomInfiniteScrollView<Item, BagItem> customSV;
private void Awake()
{
showCacheStackCountBtn.onClick.AddListener(ShowCacheStackCount);
}
private void ShowCacheStackCount()
{
Debug.LogError("UICommonItemPool<BagItem>.Instance.m_freeItems.Count : " + UICommonItemPool<BagItem>.Instance.m_freeItems.Count);
Debug.LogError("UICommonItemPool<BagItem>.Instance.m_usingItems.Count : " + UICommonItemPool<BagItem>.Instance.m_usingItems.Count);
Debug.LogError("--------------------------------------------------");
}
void Start()
{
UICommonItemPool<BagItem>.Instance.ItemRes = bagItem.gameObject;
customSV = new CustomInfiniteScrollView<Item, BagItem>();
var size = (bagItem.transform as RectTransform).sizeDelta;
customSV.InitScrollView(content, new Vector2(0, 1140), new Vector2Int(0, 3), new Vector2Int(60, 10));
customSV.InitItemInfo(size, "Closet/BagItem", bagItem);
customSV.InitItemData(GetItems());
}
private void Update()
{
customSV.CheckShowOrHideItemAsync();
}
private List<Item> GetItems()
{
List<Item> items = new List<Item>();
for (int i = 0; i < 100000; i++)
{
Item item = new Item();
item.id = i;
item.num = i;
items.Add(item);
}
return items;
}
}
}