1.功能需求
UI页面制作中经常有多单元格的列表组件,像邮件页、背包页面、商店页面等。
或者像下面这样的数量比较少的标签栏。
这些Items一般在unity的Scroll Rect列表组件下,或者是使用布局组件排版的父物体下。
这里要实现一个组件,使用方法可根据数据控制item列表的生成,并且可以控制item的数据填充或者添加点击事件等;在数据更新的时候刷新页面,复用已经生成过的item只填充数据,数量不足时再进行创建并填充数据。
2.组件代码
using System;
using System.Collections.Generic;
using UnityEngine;
public class ItemList : MonoBehaviour
{
private readonly List<GameObject> mItemList = new List<GameObject>();
public GameObject ItemTemplate;
public int Count => mItemList.Count;
public GameObject this[int index] => mItemList[index];
public void Reset()
{
for (int i = 0; i < mItemList.Count; i++)
{
mItemList[i].SetActive(false);
}
}
public void Reset(int maxValue)
{
for (int i = 0; i < mItemList.Count; i++)
{
mItemList[i].SetActive(i + 1 <= maxValue);
}
}
public void ResetDestroy()
{
for (int i = mItemList.Count; i > 0; i--)
{
DestroyImmediate(mItemList[i - 1]);
}
mItemList.Clear();
}
public void Refresh<T>(int index, T data, Action<T, GameObject> draw, bool isActive = true)
{
if (mItemList == null) return;
if (index < mItemList.Count)
{
mItemList[index].SetActive(isActive);
draw(data, mItemList[index]);
}
else
{
var newItem = Instantiate(ItemTemplate);
newItem.SetActive(isActive);
newItem.transform.SetParent(ItemTemplate.transform.parent, false);
mItemList.Add(newItem);
draw(data, newItem);
}
}
public void Refresh<T>(int index, T data, Action<T, GameObject, object[]> draw, bool isActive = true, params object[] followData)
{
if (mItemList == null) return;
if (index < mItemList.Count)
{
mItemList[index].SetActive(isActive);
draw(data, mItemList[index], followData);
}
else
{
var newItem = Instantiate(ItemTemplate);
newItem.SetActive(isActive);
newItem.transform.SetParent(ItemTemplate.transform.parent, false);
mItemList.Add(newItem);
draw(data, newItem, followData);
}
}
public void RefreshData<T>(int index, T data, Action<int, T, GameObject> draw, bool isActive = true)
{
if (mItemList == null) return;
if (index < mItemList.Count)
{
mItemList[index].SetActive(isActive);
draw(index, data, mItemList[index]);
}
else
{
var newItem = Instantiate(ItemTemplate);
newItem.SetActive(isActive);
newItem.transform.SetParent(ItemTemplate.transform.parent, false);
mItemList.Add(newItem);
draw(index, data, newItem);
}
}
public void UpInsert<T>(int index, T data, Action<T, GameObject> draw)
{
if (mItemList == null)
{
}
else
{
var newItem = Instantiate(ItemTemplate);
newItem.SetActive(true);
newItem.transform.SetParent(ItemTemplate.transform.parent, false);
newItem.transform.SetAsFirstSibling();
//mItemList.Insert(index, newItem);
draw(data, newItem);
}
}
public void DownInsert<T>(int index, T data, Action<T, GameObject> draw)
{
if (mItemList == null)
{
}
else
{
var newItem = Instantiate(ItemTemplate);
newItem.SetActive(true);
newItem.transform.SetParent(ItemTemplate.transform.parent, false);
newItem.transform.SetAsLastSibling();
//mItemList.Insert(index, newItem);
draw(data, newItem);
}
}
public GameObject GetGoItem(int index)
{
if (index >= mItemList.Count) return null;
return mItemList[index];
}
public List<GameObject> GetItemList()
{
return mItemList;
}
private void OnDestroy()
{
foreach (var item in mItemList) Destroy(item);
mItemList.Clear();
}
}
3.使用方法
ItemList挂载在items的父物体上,为ItemTemplate赋值,ItemTemplate制作之后设置为未激活;
根据数据数量,使用for循环,循环体使用itemList.Refresh()方法设置item的生成和数据设置;
public ItemList itemList;
private List<string> dataList = new List<string>() { "1", "2", "3", "4", "5" };
private void Awake()
{
RefreshList();
}
private void RefreshList()
{
if (itemList != null)
{
itemList.Reset();
for (int i = 0; i < 5; i++)
{
itemList.Refresh(i, dataList[i], (data, obj) =>
{
obj.GetComponentInChildren<Text>().text = data;
obj.transform.localPosition = new Vector3(0, 0, 0) + Vector3.down * i * 100;
});
}
}
} public ItemList itemList;
List<string> dataList = new List<string>() { "1", "2", "3", "4", "5" };
private void RefreshList()
{
if (itemList!=null)
{
itemList.Reset();
for (int i = 0; i < 5; i++)
{
itemList.Refresh(i, dataList[i], (data, obj) =>
{
obj.GetComponentInChildren<Text>().text = data;
obj.transform.localPosition = new Vector3(0, 0, 0) + Vector3.down * i * 100;
});
}
}
}
在数据更新时候再次填充数据之前应调用itemList.Reset();清理重置数据,但已经创建的item只是暂时关闭,在需要一个item的时候会优先使用。
如未注明 , 均为原创丨欢迎转载,转载请注明原文链接。