[Unity3D]ScrollView Item循环利用

先上Unity里面的组件的详情

Paste_Image.png
Paste_Image.png
Paste_Image.png
Paste_Image.png

接着是代码

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ScrollViewCircle : MonoBehaviour
{
    #region 

    //滚动的ScrollView//
    public ScrollRect m_ScrollRect;
    //Mask蒙板,目标是显示区域内的Item,避免在更换Item位置的时候造成直接的视觉误差//
    public RectTransform m_ViewRect;
    //ScrollView里的Content//
    public RectTransform m_Content;
    //Item的宽和高//
    public Vector2 m_ItemSize;
    //Content的padding//
    public RectOffset m_ContentPadding;
    //预设的物体//
    public Item m_ItemPrefab;

    public int m_MaxRowCount = 100;
    public int m_MaxColumnCount = 3;

    #endregion

    private int m_ShowMaxRowCount;
    private List<ItemData> m_ItemDataList;
    Dictionary<int, List<Item>> m_DictToShowingItem = new Dictionary<int, List<Item>>();
    //缓存池。
    Queue<List<Item>> m_CacheList = new Queue<List<Item>>();
    Queue<Item> m_CacheItemList = new Queue<Item>();

    //上一次滚动的Index//
    int lastIndex;


    // Use this for initialization
    void Start()
    {
        SetItemDataList();
        m_MaxRowCount = m_ItemDataList.Count / m_MaxColumnCount;
        m_ShowMaxRowCount = Mathf.CeilToInt(m_ViewRect.rect.height / m_ItemSize.y) + 1;
        m_Content.sizeDelta = new Vector2(m_Content.sizeDelta.x, m_ItemSize.y * m_MaxRowCount);
        m_ScrollRect.onValueChanged.AddListener(OnScrollRectValueChange);
        lastIndex = -1;
        this.OnItemListChange(1);
    }

    protected virtual void SetItemDataList()
    {
        if (m_ItemDataList == null)
        {
            m_MaxRowCount = m_MaxRowCount < 0 ? 50 : m_MaxRowCount;
            m_ItemDataList = new List<ItemData>(m_MaxRowCount * m_MaxColumnCount);
            for (int i = 0; i < m_MaxRowCount * m_MaxColumnCount; i++)
            {
                m_ItemDataList.Add(new ItemData() { index = i });
            }
        }
    }

    void OnScrollRectValueChange(Vector2 vect)
    {
        if (vect.y < 0 || vect.y > 1)
        {
            //Debug.Log("超出范围了,不变化!");
            return;
        }
        //vect.y 是垂直滚动进度,取值范围 [0,1]。
        //当vect = 0 时,m_Content.m_Content.anchoredPosition.y = 0。
        //当vect = 1 时,m_Content.m_Content.anchoredPosition.y = (m_Content.sizeDelta.y - m_ViewRect.rect.height)。
        float y = (1 - vect.y) * (m_Content.sizeDelta.y - m_ViewRect.rect.height);
        int index = Mathf.CeilToInt(y / m_ItemSize.y);
        this.OnItemListChange(index);
    }

    void OnItemListChange(int index)
    {
        if (lastIndex == index)
            return;
        Debug.Log("index = " + index);
        int minIndex = (index);
        int maxIndex = (index + m_ShowMaxRowCount);
        if (lastIndex < index)
        {
            //Debug.Log("往上移动!");
            for (int key = minIndex - (m_ShowMaxRowCount); key < minIndex; key++)
            {
                if (m_DictToShowingItem.TryGetValue(key, out List<Item> tempItemList))
                {
                    m_DictToShowingItem.Remove(key);
                    for (int i = 0; i < tempItemList.Count; i++)
                    {
                        EnqueueItem(tempItemList[i]);
                    }
                    EnqueueItemList(tempItemList);
                }
            }

            //移除完毕后,添加下方需要增加的Item//
            RefreshRowItem(minIndex, maxIndex);
        }
        else
        {
            //Debug.Log("往下移动!");
            for (int key = maxIndex; key >= maxIndex - 1; key--)
            {
                if (m_DictToShowingItem.TryGetValue(key, out List<Item> tempItemList))
                {
                    m_DictToShowingItem.Remove(key);
                    for (int i = 0; i < tempItemList.Count; i++)
                    {
                        EnqueueItem(tempItemList[i]);
                    }
                    EnqueueItemList(tempItemList);
                }
            }

            //移除完毕后,添加下方需要增加的Item//
            RefreshRowItem(minIndex, maxIndex);
        }
        lastIndex = index;
    }


    private void RefreshRowItem(int minRow, int maxRow)
    {
        for (int rowIndex = minRow; rowIndex < maxRow; rowIndex++)
        {
            if (rowIndex <= 0 || rowIndex > m_MaxRowCount)
                continue;
            if (!m_DictToShowingItem.ContainsKey(rowIndex))
            {
                List<Item> tempItemList = PushItemList();
                for (int columnIndex = 0; columnIndex < m_MaxColumnCount; columnIndex++)
                {
                    int index = ((rowIndex - 1) * m_MaxColumnCount + columnIndex);
                    if (index < 0 || index >= m_ItemDataList.Count)
                    {
                        continue;
                    }
                    var tempItem = PushItem();
                    var itemData = m_ItemDataList[index];
                    tempItem.OnInit(itemData);
                    SetItemPosition(tempItem, rowIndex, columnIndex);
                    tempItemList.Add(tempItem);
                }
                m_DictToShowingItem.Add(rowIndex, tempItemList);
            }
        }
    }


    private void EnqueueItem(Item item)
    {
        item.OnClear();
        m_CacheItemList.Enqueue(item);
    }

    private Item PushItem()
    {
        if (m_CacheItemList.Count == 0)
        {
            m_CacheItemList.Enqueue(Instantiate(m_ItemPrefab, m_Content) as Item);
        }
        Item tempItem = m_CacheItemList.Dequeue();
        return tempItem;
    }

    private void EnqueueItemList(List<Item> itemlist)
    {
        itemlist.Clear();
        m_CacheList.Enqueue(itemlist);
    }

    private List<Item> PushItemList()
    {
        if (m_CacheList.Count == 0)
        {
            m_CacheList.Enqueue(new List<Item>());
        }
        List<Item> result = m_CacheList.Dequeue();
        return result;
    }

    private void SetItemPosition(Item item, int rowIndex, int columnIndex)
    {
        item.GetComponent<RectTransform>().anchoredPosition = new Vector2(
            (columnIndex - ((m_MaxColumnCount - 1) / 2f)) * m_ItemSize.x,
            -(rowIndex - 0.5f) * m_ItemSize.y);
        item._text.text = ((rowIndex - 1) * m_MaxColumnCount + columnIndex).ToString();
    }
}

Item

using UnityEngine;
using UnityEngine.UI;

public class Item : MonoBehaviour
{
    public Text _text;
    private RectTransform rectTransform;

    private void Awake()
    {
        rectTransform = this.GetComponent<RectTransform>();
        rectTransform.anchorMin = new Vector2(0.5f, 1);
        rectTransform.anchorMax = new Vector2(0.5f, 1);
        rectTransform.pivot = new Vector2(0.5f, 0.5f);
    }

    public virtual void OnInit(ItemData itemData)
    {
        _text.text = itemData.index.ToString();
    }

    public virtual void OnClear()
    {

    }
}


public class ItemData
{
    public int index = 0;
    //继承后自定义。
}

暂时就这样,还没实际应用过,不过在demo里测了,感觉还行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容