unity 无限滚动列表
小工具,留着备用~实现思路:
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; //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.gameObject.SetActive(false); } int itemCount = Mathf.Clamp(DataCount, 0, m_maxItemCount); Transform tran; for (Int32 i = 0; i < itemCount; i++) { if (i < m_itemList.Count) { tran = m_itemList; } 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; 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; 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); } } }
页:
[1]