Unity UGUI实现无限滚动列表

Demo链接​​​https://download.csdn.net/download/qq_41973169/89364284icon-default.png?t=N7T8http://Unity UGUI无限滚动列表

在游戏开发中,列表视图是一个常见的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, _itemTotalSize * i);_itemList.Add(obj);}itemPrefab.SetActive(false);}private void SetPivot(GameObject obj, float position){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);rect.anchoredPosition = new Vector2(0, -position);}else{rect.pivot = new Vector2(0, 0.5f);rect.anchorMax = new Vector2(0, 0.5f);rect.anchorMin = new Vector2(0, 0.5f);rect.anchoredPosition = new Vector2(position, 0);}}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 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.mzph.cn/bicheng/16981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手动操作很麻烦?试试这个自动加好友神器吧!

你是不是也觉得手动逐一输入号码或是微信号&#xff0c;再搜索添加很麻烦&#xff1f;试试这个自动加好友神器——个微管理系统&#xff0c;帮助你省去繁琐的手工操作&#xff0c;节省时间和精力。 首先&#xff0c;在系统上登录微信号&#xff0c;无论你有多少个微信号&#…

2024年上半年软件设计师试题及答案(回忆版)--选择题

基础知识选择题 基础知识选择题 1,2,3][4,5,6][1,2,3,4,5,6] &#xff08;总&#xff1a;1分&#xff09; &#xff08;注意&#xff1a;括号内的是截止当前题目总分&#xff09; vlan不能隔绝内外网 &#xff08;2分&#xff09; 链路层使用交换机&#xff0c;…

智慧树下做游戏

游戏开发工程师致力于游戏总体设计 &#xff0c;负责游戏开发工具和运营维护工具的设计与开发 &#xff0c;并配合主程序完成游戏架构及各大功能的设计、开发、调试和其他技术支持 就业方向&#xff1a; 一般有客户端游戏开发和服务器游戏开发 客户端开发&#xff1a; 主要负…

光伏开发是用什么工具提高效率?

随着全球对可再生能源的日益重视&#xff0c;光伏产业作为其中的佼佼者&#xff0c;已经取得了长足的发展。然而&#xff0c;如何提高光伏开发的效率&#xff0c;降低成本&#xff0c;成为了业内关注的焦点。本文将探讨光伏开发过程中所使用的工具&#xff0c;以及这些工具如何…

设计软件有哪些?建模和造型工具篇(2),渲染100邀请码1a12

之前介绍了一批建模工具&#xff0c;这次我们继续介绍。 1、Forest Pack Forest Pack是由iToo Software公司开发的3ds Max插件&#xff0c;专门用于创建大规模自然环境。它提供了丰富的植被和物体库&#xff0c;用户可以快速创建树木、植物、岩石等元素&#xff0c;并将它们分…

Android面试题之Kotlin常见集合操作技巧

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 list 创建和修改 不可变list,listOf var list listOf("a","d","f") println(list.getOrElse(3){"Unkn…

Kubernetes可视化界面之DashBoard

1.1 DashBoard Kubernetes Dashboard 是 Kubernetes 集群的一个开箱即用的 Web UI&#xff0c;提供了一种图形化的方式来管理和监视 Kubernetes 集群中的资源。它允许用户直接在浏览器中执行许多常见的 Kubernetes 管理任务&#xff0c;如部署应用、监控应用状态、执行故障排查…

用循环神经网络预测股价

循环神经网络可以用来对时间序列进行预测&#xff0c;之前我们在介绍循环神经网络RNN,LSTM和GRU的时候都用到了正弦函数预测的例子&#xff0c;其实这个例子就是一个时间序列。而在众多的时间序列例子中&#xff0c;最普遍的就是股价的预测了&#xff0c;股价序列是一种很明显的…

链表练习题

返回倒数第K个节点 快慢指针 让快指针先走k步&#xff0c;再使得快指针与慢指针同时走一步&#xff0c;这样没有开额外空间&#xff0c;空间复杂度较低。 代码实现如下&#xff1a; struct ListNode {int val;struct ListNode* next;}; int kthToLast(struct ListNode* head…

第 52 期:MySQL 半同步复制频繁报错

社区王牌专栏《一问一实验&#xff1a;AI 版》全新改版归来&#xff0c;得到了新老读者们的关注。其中不乏对 ChatDBA 感兴趣的读者前来咨询&#xff0c;表达了想试用体验 ChatDBA 的意愿&#xff0c;对此我们表示感谢 &#x1f91f;。 目前&#xff0c;ChatDBA 还在最后的准备…

el-table实现合并特定列的所有行

el-table实现合并特定列的所有行 示例&#xff1a; 在这里插入图片描述 const objectSpanMethod ({ row, column, rowIndex, columnIndex }) > {if (columnIndex 5 || columnIndex 7) {// 就是只保留第一行&#xff0c;其他直接不要&#xff0c;然后行数是列表长度if …

2024年03月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 下列哪个命令,可以将2024转换成’2024’ 呢?( ) A:str(2024) B:int(2024) C:float(2024) D:bool(2024) 答案:A 本题考察的是str() 语句,将数字转换成字符串用到的是str() 语句。 …

Java:IO

首 java.io中有百万计的类&#xff0c;如何找到自己需要的部分&#xff1f; 流 IO涉及到一个“流”stream的概念&#xff0c;可以简单理解成数据从一个源头到一个目的地。明白数据从哪来&#xff0c;要到哪里去&#xff0c;数据流中是字节还是字符之后&#xff0c;才能找到自…

由于找不到d3dx9_39.dll,无法继续执行代码的5种解决方法

在现代科技发展的时代&#xff0c;电脑已经成为我们生活中不可或缺的一部分。然而&#xff0c;由于各种原因&#xff0c;我们可能会遇到一些电脑问题&#xff0c;其中之一就是“d3dx9_39.dll丢失”。这个问题可能会导致我们在运行某些游戏或应用程序时遇到错误提示&#xff0c;…

新品 | Forge® 1GigE IP67工业相机助力智能农业、食品和饮料行业

近日&#xff0c;51camera的合作伙伴Teledyne FLIR IIS推出Forge 1GigE IP67,它是Forge系列的最新工业相机&#xff0c;旨在在恶劣的工业环境中运行&#xff0c;同时确保高效的生产能力。Forge 1GigE IP67致力于为工厂自动化提供先进成像系统的最新产品。 Forge 1GigE IP67相机…

MyBatis多数据源配置与使用,基于ThreadLocal+AOP

导读 MyBatis多数据源配置与使用其一其二1. 引依赖2. 配置文件3. 编写测试代码4. 自定义DynamicDataSource类5. DataSourceConfig配置类6. AOP与ThreadLocal结合7. 引入AOP依赖8. DataSourceContextHolder9. 自定义注解UseDB10. 创建切面类UseDBAspect11. 修改DynamicDataSourc…

PTA 计算矩阵两个对角线之和

计算一个nn矩阵两个对角线之和。 输入格式: 第一行输入一个整数n(0<n≤10)&#xff0c;第二行至第n1行&#xff0c;每行输入n个整数&#xff0c;每行第一个数前没有空格&#xff0c;每行的每个数之间各有一个空格。 输出格式: 两条对角线元素和&#xff0c;输出格式见样例…

Android存储系统成长记

用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章 本文概要 您一定使用过Context的getFileStreamPath方法或者Environment的getExternalStoragePublicDirectory方法&#xff0c;甚至还有别的方法把数据存储到文件中&#xff0c;这些都是存储系统提供的服务&#x…

PTA 判断两个矩阵相等

Peter得到两个n行m列矩阵&#xff0c;她想知道两个矩阵是否相等&#xff0c;请你用“Yes”&#xff0c;“No”回答她&#xff08;两个矩阵相等指的是两个矩阵对应元素都相等&#xff09;。 输入格式: 第一行输入整数n和m&#xff0c;表示两个矩阵的行与列&#xff0c;用空格隔…

修改元组元素

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 场景模拟&#xff1a;伊米咖啡馆&#xff0c;由于麝香猫咖啡需求量较大&#xff0c;库存不足&#xff0c;店长想把它换成拿铁咖啡。 实例08 将麝香猫…