Unity UGUI实现无限滚动列表

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.rhkb.cn/news/339459.html

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

相关文章

贪心算法拓展(反悔贪心)

相信大家对贪心算法已经见怪不怪了&#xff0c;但是一旦我们的决策条件会随着我们的步骤变化&#xff0c;我们该怎么办呢&#xff1f;有没有什么方法可以反悔呢&#xff1f; 今天就来讲可以后悔的贪心算法&#xff0c;反悔贪心。 https://www.luogu.com.cn/problem/CF865Dhttp…

100页2秒?我们为什么需要这样的文档解析速度

近期&#xff0c;TextIn通用文档解析完成最新一版产品迭代&#xff0c;将100页文档解析速度提升至最快2秒以内。 P50&#xff08;百页&#xff09; P90&#xff08;百页&#xff09; P95&#xff08;百页&#xff09; P99&#xff08;百页&#xff09; 平均&#xff08;单页…

C++:list模拟实现

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;list模拟实现》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 如果本篇文章对你有帮助&#xff0c;还请各位点点赞&#xff01;&#xf…

vue不同页面切换的方式(Vue动态组件)

v-if实现 <!--Calender.vue--> <template><a-calendar v-model:value"value" panelChange"onPanelChange" /></template> <script setup> import { ref } from vue; const value ref(); const onPanelChange (value, mod…

MySQL—函数—数值函数(基础)

一、引言 首先了解一下常见的数值函数哪些&#xff1f;并且直到它们的作用&#xff0c;并且演示这些函数的使用。 二、数值函数 常见的数值函数如下&#xff1a; 注意&#xff1a; 1、ceil(x)、floor(x) &#xff1a;向上、向下取整。 2、mod(x,y)&#xff1a;模运算&#x…

基于Springboot + vue实现的文化民俗网站

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

字节裁员!开启裁员新模式。。

最近&#xff0c;互联网圈不太平&#xff0c;裁员消息此起彼伏。而一向以“狼性文化”著称的字节跳动&#xff0c;却玩起了“低调裁员”&#xff0c;用一种近乎“温柔”的方式&#xff0c;慢慢挤掉“冗余”的员工。 “细水长流”&#xff1a;裁员新模式&#xff1f; 不同于以往…

2024年Google算法更新打击低质量(如AI生成)内容后,英文SEO优化人员该如何调整谷歌SEO优化策略?

3月5日&#xff0c;谷歌发布了2024年的首次算法更新。与以往更新不同&#xff0c;本次更新更加复杂&#xff0c;这次更新旨在提高搜索结果的质量和相关性&#xff0c;可能对外贸网站排名和流量产生显著影响。也将产生更大的网站数据波动。但在担心自己的网站数据受到影响之前&a…

【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日内容 二、&#x1f30f;前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、&#x1f697;SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…

数据挖掘 | 实验三 决策树分类算法

文章目录 一、目的与要求二、实验设备与环境、数据三、实验内容四、实验小结 一、目的与要求 1&#xff09;熟悉决策树的原理&#xff1b; 2&#xff09;熟练使用sklearn库中相关决策树分类算法、预测方法&#xff1b; 3&#xff09;熟悉pydotplus、 GraphViz等库中决策树模型…

盘点2024年还在活跃发版的开源私有网盘项目附源码链接

时不时的会有客户上门咨询&#xff0c;丰盘ECM是不是开源项目&#xff0c;源码在哪里可以下载&#xff1b;如果需要和内部其他系统做集成&#xff0c;购买商业版的话&#xff0c;能否提供源代码做二次开发呢&#xff0c;等等诸多问题。 这里做个统一回复&#xff0c;丰盘ECM产…

Docker安装极简版(三分钟搞定)

什么是Docker? Docker是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 化。容器是…

MLPerf storage基准测试

MLPerf 基准测试 什么是 MLPerf&#xff1f;MLPerf™ 基准测试由来自学术界、研究实验室和行业的 AI 领导者联盟 MLCommons 开发&#xff0c;旨在对硬件、软件和服务的训练和推理性能进行无偏评估。它们都在规定的条件下进行。为了保持在行业趋势的前沿&#xff0c;MLPerf 不断…

0基础认识C语言(理论知识)

为了给0基础一个舒服的学习路径&#xff0c;就有了这个专栏希望带大家一起进步。 话不多说&#xff0c;开始正题。 一、C语言的一段小历史 C语言的设计要追溯到20世纪60年代末和70年代初&#xff0c;在那个时代美国有这么一号人叫做丹尼斯.里奇&#xff0c;他和同事肯.汤普逊…

计算机网络学习实践:DHCP跨网段动态分配IP

计算机网络学习实践&#xff1a;DHCP跨网段动态分配IP 1.实验准备 实验环境&#xff1a;思科的模拟器 实验设备&#xff1a; 1个服务器&#xff0c;2个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;4个PC机&#xff0c;1个路由器 三个网段 192.168.1.0 255.…

一些智能音箱类的软硬件方案

主要参考资料 Rabbit R1: https://www.rabbit.tech/rabbit-r1 mediatek-helio-p35: https://www.mediatek.com/products/smartphones-2/mediatek-helio-p35 NSdisplay: https://www.nsdisplay.com/ai-holobox-mini/ai-holobox-mini.html RK3566: https://www.rock-chips.com/a/…

Java学习Lambda表达式

Lambda表达式 有且只有一个未实现的方法叫做Lambda表达式&#xff0c;可以实现函数式编程 // 这个注解是用来检查你写的函数是否是函数式接口 FunctionalInterfaceinterface Myinterface {int sum(int a, int b);default String priteTitle(String name, int age, String sex)…

ASP+ACCESS酒店预定管理系统

【摘要】宏都大酒店管理信息系统中不能通过互联网方式进行客房预订&#xff0c;通过本次设计主要实现通过互联网方式进行客房预订。让客户足不出户坐在家里就能预订出自己想要的客房。主要功能有&#xff1a;酒店简介、客房简介、客房报价、客房预订信息提交&#xff0c;预订信…

Flutter基础 -- Dart 语言 -- 进阶使用

目录 1. 泛型 generics 1.1 泛型使用 1.2 泛型函数 1.3 构造函数泛型 1.4 泛型限制 2. 异步 async 2.1 异步回调 then 2.2 异步等待 await 2.3 异步返回值 3. 生成器 generate &#xff08;了解&#xff09; 3.1 同步生成器 sync* 使用 sync* 的场景 总结 3.2 异…

关于nodejs单线程

Node是使用C++语言写的一款JavaScrip解析器。 高并发 一般来说,高并发的解决方案就是多线程模型,服务器为每隔客户端请求分配一个线程,使用同步I/o,比如Apache就是这种策略,由于I/O一般都是耗时操作,因为这种策略很难实现高性能,但非常简单,可以实现复杂的交互逻辑。…