美文网首页
unity 无限滚动列表

unity 无限滚动列表

作者: 流飞飞FW | 来源:发表于2021-04-01 11:49 被阅读0次

小工具,留着备用~
实现思路:
1.生成列表之前将所有数据准备好,放入List中,content的高度在初始化时根据数据长度设置好。
2.滚动时取索引区间的数据,有几个索引就显示几行item。
3.滚动列表只负责显示,每个item上的内容由调用者控制:SetItemInfo(Transform item, int index)。

效果:

QQ录屏20210401112927.mp4_1617247824.gif

调用方式:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/*
    des:循环列表测试
    author:lfw
*/
public class TestPanel : MonoBehaviour
{
        InfinityScrollList m_scrollList;                    //无限滚动列表
        List<string> m_dataList = new List<string>(100);    //准备好的数据

        public override void Awake()
        {          
            var scroll = Transform.Find("Scroll View").GetComponent<ScrollRect>();
            var item = ObjectManager.Instance.InstantiateObject("Assets/Res/Prefabs/Item.prefab");

            for(int i = 0; i < 20; i++)
                m_dataList.Add("数据" + i);

            m_scrollList = new Util.InfinityScrollList(scroll);
            m_scrollList.Init(item, 6, m_dataList.Count, SetItemInfo);    //初始化
        }
        //自定义填充函数
        private void SetItemInfo(Transform item, int index)
        {
            item.Find("Text").GetComponent<Text>().text = m_dataList[index];
            //var btn = item.transform.Find("Button").GetComponent<Button>();
            //btn.onClick.RemoveAllListeners();
            //btn.onClick.AddListener(
            //    () =>
            //    {
            //        m_dataList.RemoveAt(index);
            //        m_scrollList.DataCount -= 1;
            //        m_scrollList.DoForceUpdate(false);
            //    });
        }
}

代码实现:
InfinityScrollList .cs

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/*
    des:循环列表类
    author:lfw
*/
class InfinityScrollList
{
        int m_headIndex = 0;                                  //顶部显示的数据索引
        int m_tailIndex = 0;                                  //最底部显示数据索引
        float m_itemHeight = 0;                               //item高度
        float m_topPading = 0;                                //距顶部边距
        float m_spacing = 0;                                  //行间距
        int m_maxItemCount;                                   //最大item数量(最好总高度刚好超过滚动框高度)
        
        Action<Transform, int> m_setInfoCallback;             //给每个item设置显示内容的函数
        List<Transform> m_itemList = new List<Transform>();   //item列表
        GameObject m_itemPrefab;
        ScrollRect m_scrollView;
        Transform m_content;
        RectTransform m_contentRect;

        public int DataCount { get; set; } = 0;                //待填充数据数量    

        public InfinityScrollList(ScrollRect scrollView)
        {

            m_headIndex = 0;
            m_tailIndex = 0;
            m_scrollView = scrollView;
            m_content = scrollView.content;
            m_contentRect = m_content.GetComponent<RectTransform>();
            m_scrollView.onValueChanged.AddListener(this.OnValueChanged);
        }

        /// <summary>
        /// 初始化必要数据
        /// </summary>
        /// <param name="itemPrefab">item预制体</param>
        /// <param name="maxItem">最大item数量</param>
        /// <param name="maxData">数据数量</param>
        /// <param name="SetItemCallBack">修改item信息的回调</param>
        public void Init(GameObject itemPrefab, int maxItem, int maxData, Action<Transform, int> setItemCallback = null)
        {
            m_itemPrefab = itemPrefab;
            m_headIndex = 0;
            m_tailIndex = 0;
            m_maxItemCount = maxItem;
            DataCount = maxData;
            m_setInfoCallback = setItemCallback;
            m_itemHeight = itemPrefab.GetComponent<RectTransform>().rect.height + m_spacing;
            m_contentRect.sizeDelta = new Vector2(m_contentRect.sizeDelta.x, m_itemHeight * DataCount + m_topPading);

            UpdateContent();
        }

        /// <summary>
        /// 数据发生变化时刷新item显示内容
        /// </summary>
        /// <param name="toTop"> 是否回到顶部</param>
        public void DoForceUpdate(bool toTop)
        {
            if (toTop)
            {
                m_headIndex = 0;
            }
            UpdateContent();
        }

        /// <summary>
        /// 根据首尾数据索引,刷新item内容
        /// </summary>
        private void UpdateContent()
        {
            for (int i = 0; i < m_itemList.Count; i++)
            {
                if (i >= DataCount)
                    m_itemList[i].gameObject.SetActive(false);
            }

            int itemCount = Mathf.Clamp(DataCount, 0, m_maxItemCount);
            //修正从后向前移除节点时,尾部索引越界的bug
            if (m_headIndex + itemCount > DataCount)
            {
                m_headIndex = DataCount - itemCount;
            }

            Transform tran;
            for (Int32 i = 0; i < itemCount; i++)
            {
                if (i < m_itemList.Count)
                {
                    tran = m_itemList[i];
                }
                else
                {
                    var item = m_itemPrefab.Instantiate();
                    tran = item.transform;
                    tran.GetComponent<RectTransform>().anchorMin = new Vector2(0.5f, 1);
                    tran.GetComponent<RectTransform>().anchorMax = new Vector2(0.5f, 1);
                    tran.GetComponent<RectTransform>().pivot = new Vector2(0.5f, 1);
                    tran.SetParent(m_content, false);
                    m_itemList.Add(tran);
                }
                int index = m_headIndex + i;
                tran.name = index.ToString();
                tran.GetComponent<RectTransform>().anchoredPosition = new Vector2(0, -m_itemHeight * index - m_topPading);

                m_setInfoCallback?.Invoke(tran, index); //更新内容
            }
            m_tailIndex = m_headIndex + (itemCount - 1);

            m_contentRect.sizeDelta = new Vector2(m_contentRect.sizeDelta.x, m_itemHeight * DataCount + m_topPading);
        }

        private void OnValueChanged(Vector2 v2)
        {
            if (m_itemList.Count <= 0)
            {
                return;
            }

            //向上滚动
            while (m_contentRect.anchoredPosition.y > (m_headIndex + 1) * m_itemHeight && m_tailIndex != DataCount - 1)
            {

                Transform _first = m_itemList[0];
                RectTransform _firstRect = _first.GetComponent<RectTransform>();

                //将顶部item移到底部
                m_itemList.RemoveAt(0);
                m_itemList.Add(_first);

                m_headIndex++;
                m_tailIndex++;

                _firstRect.anchoredPosition = new Vector2(0, -m_tailIndex * m_itemHeight - m_topPading);

                //修改显示
                _first.name = m_tailIndex.ToString();
                m_setInfoCallback?.Invoke(_first, m_tailIndex);
            }

            //向下滚动
            while (m_contentRect.anchoredPosition.y < m_headIndex * m_itemHeight && m_headIndex != 0)
            {
                Transform _last = m_itemList[m_itemList.Count - 1];
                RectTransform _lastRect = _last.GetComponent<RectTransform>();

                m_itemList.RemoveAt(m_itemList.Count - 1);
                m_itemList.Insert(0, _last);

                m_headIndex--;
                m_tailIndex--;

                _lastRect.anchoredPosition = new Vector2(0, -m_headIndex * m_itemHeight - m_topPading);
                _last.name = m_headIndex.ToString();
                m_setInfoCallback?.Invoke(_last, m_headIndex);
            }
        }
    }

相关文章

网友评论

      本文标题:unity 无限滚动列表

      本文链接:https://www.haomeiwen.com/subject/qhftkltx.html