Unity UGUI实现无限滚动列表

devtools/2024/10/11 6:58:10/

Demo链接: ​​​https://download.csdn.net/download/qq_41973169/89364284

在游戏开发中,列表视图是一个常见的UI组件。实现一个高效的列表视图尤其重要,尤其是在需要展示大量数据时。本文将介绍如何在Unity中实现一个高效的无限滚动列表,包括两个关键脚本:InfiniteScroll 和 ListItem 两个脚本 话不多说直接上代码

Unity版本2022.3.X

InfiniteScroll.cs

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System;public class InfiniteScroll : MonoBehaviour
{public delegate void ItemDelegate(int itemDataIndex, int slotID);public ItemDelegate OnUpdateItemImpl;// 更新Item回调函数public enum ScrollDirection{Vertical,Horizontal}public GameObject itemPrefab;[Header("横向滑动表示宽度; 纵向滑动表示高度")]public float itemSize;[Header("列表项间距")]public float spacing; // 列表项间距[Header("最大可见列表项数量")]public int maxVisibleItemCount;[Header("滑动方向")]public ScrollDirection scrollDirection = ScrollDirection.Vertical;private ScrollRect _scrollRect;private RectTransform _contentRectTransform;private int _firstVisibleIndex; // 第一个可见列表项的索引private int _lastVisibleIndex; // 最后一个可见列表项的索引private List<GameObject> _itemList; // 列表项对象列表private float _itemTotalSize; // 列表项总尺寸(包括间距)private int _totalItemDataCount; // item总共数据数量private void Awake(){_itemTotalSize = itemSize + spacing;_itemList = new List<GameObject>();_scrollRect = GetComponent<ScrollRect>();_contentRectTransform = _scrollRect.content.GetComponent<RectTransform>();_scrollRect.onValueChanged.AddListener(OnScrollChanged);}public void Init(){for (int i = 0; i < maxVisibleItemCount; i++){int slotID = i + 1;GameObject obj = Instantiate(itemPrefab, _contentRectTransform);ListItem listItem = obj.GetComponent<ListItem>();listItem.Init(this);listItem.SetSlotID(slotID);obj.name = slotID.ToString();SetPivot(obj);_itemList.Add(obj);}itemPrefab.SetActive(false);}private void SetPivot(GameObject obj){RectTransform rect = obj.GetComponent<RectTransform>();if (scrollDirection == ScrollDirection.Vertical){rect.pivot = new Vector2(0.5f, 1);rect.anchorMax = new Vector2(0.5f, 1);rect.anchorMin = new Vector2(0.5f, 1);}else{rect.pivot = new Vector2(0, 0.5f);rect.anchorMax = new Vector2(0, 0.5f);rect.anchorMin = new Vector2(0, 0.5f);}}private void OnScrollChanged(Vector2 position){if (scrollDirection == ScrollDirection.Vertical){Func<bool> condition1 = () =>{// 如果Content的Y轴坐标大于上面第二个Item 并且最后的下标不是数据的最后一个则表示向下滑动可以更新Itemreturn _contentRectTransform.anchoredPosition.y > (_firstVisibleIndex + 1) * _itemTotalSize && _lastVisibleIndex < _totalItemDataCount - 1;};Func<bool> condition2 = () =>{// 如果Content的Y轴坐标小于上面第一个Item 并且最上面的索引不为0 则表示向上滑动可以更新Itemreturn _contentRectTransform.anchoredPosition.y < _firstVisibleIndex * _itemTotalSize && _firstVisibleIndex > 0;};UpdateItems(condition1, condition2);}else{Func<bool> condition1 = () =>{// 如果Content的X轴坐标大于右边第二个Item 并且最后的下标不是数据的最后一个则表示向右滑动可以更新Itemreturn Mathf.Abs(_contentRectTransform.anchoredPosition.x) > (_firstVisibleIndex + 1) * _itemTotalSize && _lastVisibleIndex < _totalItemDataCount - 1;};Func<bool> condition2 = () =>{// 如果Content的X轴坐标小于左边第一个Item 并且最上面的索引不为0 则表示向左滑动可以更新Itemreturn Mathf.Abs(_contentRectTransform.anchoredPosition.x) < _firstVisibleIndex * _itemTotalSize && _firstVisibleIndex > 0;};UpdateItems(condition1, condition2);}}private void UpdateItemUI(GameObject obj, int dataIndex){ListItem listItem = obj.GetComponent<ListItem>();listItem.SetDataIndex(dataIndex);listItem.UpdateUI();}private void UpdateItems(Func<bool> condition1, Func<bool> condition2){while (condition1()){GameObject first = _itemList[0];RectTransform rectTrans = first.GetComponent<RectTransform>();_itemList.RemoveAt(0);_itemList.Add(first);rectTrans.anchoredPosition = scrollDirection == ScrollDirection.Horizontal ?new Vector2((_lastVisibleIndex + 1) * _itemTotalSize, 0) :new Vector2(0, -(_lastVisibleIndex + 1) * _itemTotalSize);_firstVisibleIndex += 1;_lastVisibleIndex += 1;UpdateItemUI(first, _lastVisibleIndex + 1);}while (condition2()){GameObject last = _itemList[_itemList.Count - 1];RectTransform rectTrans = last.GetComponent<RectTransform>();_itemList.RemoveAt(_itemList.Count - 1);_itemList.Insert(0, last);rectTrans.anchoredPosition = scrollDirection == ScrollDirection.Horizontal ? new Vector2((_firstVisibleIndex - 1) * _itemTotalSize, 0) :new Vector2(0, -(_firstVisibleIndex - 1) * _itemTotalSize);_firstVisibleIndex -= 1;_lastVisibleIndex -= 1;UpdateItemUI(last, _firstVisibleIndex + 1);}}public void RefreshList(){_firstVisibleIndex = 0;for (int i = 0; i < _itemList.Count; i++){GameObject obj = _itemList[i];obj.SetActive(i < _totalItemDataCount);if (i < _totalItemDataCount){_lastVisibleIndex = i;UpdateItemUI(obj, i + 1);}float position = _itemTotalSize * i;RectTransform rect = obj.GetComponent<RectTransform>();if (scrollDirection == ScrollDirection.Vertical){rect.anchoredPosition = new Vector2(0, -position);}else{rect.anchoredPosition = new Vector2(position, 0);}}float size = _itemTotalSize * _totalItemDataCount - spacing;if (scrollDirection == ScrollDirection.Vertical){_contentRectTransform.sizeDelta = new Vector2(_contentRectTransform.sizeDelta.x, size);}else{_contentRectTransform.sizeDelta = new Vector2(size, _contentRectTransform.sizeDelta.y);}_contentRectTransform.anchoredPosition = Vector2.zero;}public void SetTotalItemDataCount(int count){_totalItemDataCount = count;}
}

ListItem.cs

using UnityEngine;
using UnityEngine.UI;public class ListItem : MonoBehaviour
{public Text itemText;private InfiniteScroll _infiniteScroll;private int _slotID;private int _dataIndex;public void Init(InfiniteScroll infiniteScroll){_infiniteScroll = infiniteScroll;}public void SetSlotID(int slotID){_slotID = slotID;}public void SetDataIndex(int dataIndex){_dataIndex = dataIndex;}public void UpdateUI(){itemText.text = $"{_dataIndex} SlotID{_slotID}";if (_infiniteScroll.OnUpdateItemImpl != null){_infiniteScroll.OnUpdateItemImpl.Invoke(_dataIndex, _slotID);}else{Debug.LogError("InfiniteScroll.OnUpdateItemImpl == null");}}
}

测试代码

MyTest.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class MyTest : MonoBehaviour
{public InfiniteScroll horizontalInfiniteScroll;public InfiniteScroll verticalInfiniteScroll;void Start(){horizontalInfiniteScroll.Init();verticalInfiniteScroll.Init();horizontalInfiniteScroll.OnUpdateItemImpl = (dataIndex, slotID) =>{Debug.LogError($"horizontalInfiniteScroll dataIndex:{dataIndex}, slotID:{slotID}");};verticalInfiniteScroll.OnUpdateItemImpl = (dataIndex, slotID) =>{Debug.LogError($"verticalInfiniteScroll dataIndex:{dataIndex}, slotID:{slotID}");};horizontalInfiniteScroll.SetTotalItemDataCount(100);verticalInfiniteScroll.SetTotalItemDataCount(100);horizontalInfiniteScroll.RefreshList();verticalInfiniteScroll.RefreshList();}
}

 测试效果

场景树UI布局 

脚本挂载

 


http://www.ppmy.cn/devtools/44985.html

相关文章

vue3 前端实现导出下载pdf文件

这样的数据实现导出 yourArrayBufferOrByteArray 就是后端返回数据 // 创建Blob对象const blob new Blob([new Uint8Array(res)], { type: application/pdf })// 创建一个表示该Blob的URLconst url URL.createObjectURL(blob);// 创建一个a标签用于下载const a document.cr…

高性能服务器网络模型详解

1999年Dan Kegel在发表的论文中提出了The C10K problem&#xff0c;这篇论文对传统服务器架构处理大规模并发连接时的挑战进行了详细描述&#xff0c;并提出了一些解决方案和优化技术。这里的C指的是Concurrent(并发)的缩写&#xff0c;C10K问题是指怎么在单台服务器上并发一万…

前端 CSS 经典:3D Hover Effect 效果

前言&#xff1a;有趣的 3D Hover Effect 效果&#xff0c;通过 js 监听鼠标移动&#xff0c;动态赋值 rotateX&#xff0c;rotateY 的旋转度来实现。 效果图&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta …

python作业:实现一个任务列表管理系统,使用到python类、对象、循环等知识

实现一个简单的任务列表管理系统&#xff0c;可以用于python学习的作业或者练习。系统的功能包括&#xff1a; 用户可以添加任务、查看任务列表、标记任务为已完成&#xff0c;以及删除任务。 代码如下&#xff1a; class Task: def __init__(self, name, completedFalse):…

修改ModelLink在RTX3090完成预训练、微调、推理、评估以及TRT-LLM转换、推理、性能测试

修改ModelLink在RTX3090完成预训练、微调、推理、评估以及TRT-LLM转换、推理、性能测试 1 参考文档2 测试环境3 创建容器4 安装AscendSpeed、ModelLink5 下载LLAMA2-7B预训练权重和词表6 huggingface模型的推理及性能测试7.1 修改torch,deepspeed规避缺失npu环境的问题7.2 修改…

《Python学习》-- 入门篇三

一、类的定义 Python是一种动态类型语言&#xff0c;可以在运行过程中添加、修改对象的类属性。这点和JAVA不同。 # 类 # 类是对象的抽象 # 类里面的函数称为方法 # 类的命名通常遵循用首字母大写的驼峰式命名法&#xff08;CapWords&#xff0c;也称为骆驼式命名法&#xff0…

大数据信用报告分析和评估有什么意义

大数据信用这个词在现在已经是很常见的了&#xff0c;只要是申贷的朋友对它就不陌生&#xff0c;在明面上的信用资质刚刚满足审核要求&#xff0c;但又要把控风险的时候&#xff0c;这个时候大数据信用就会作为风控机构交叉核查的重要依据。那你知道大数据信用报告分析和评估有…

ros2 launch gazebo_ros gazebo.launch.py无法启动

现象&#xff1a; 我的系统是ubuntu22.04&#xff0c;ros2的版本是humble&#xff0c;当运行os2 launch gazebo_ros gazebo.launch.py命令&#xff0c;会卡死在第六行&#xff0c;gazebo也不会打开但最后单独使用gazebo则可以打开 原因&#xff1a; 没有设置环境变量 解决办法 …