【Unity】列表单元格生成ItemList

1,029 阅读2分钟

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的时候会优先使用。

如未注明 , 均为原创丨欢迎转载,转载请注明原文链接。