Unity的ScrollView无限循环滚动

本文介绍了ScrollView无限循环滚动工具ScrollCircleMaker v1.0。当ScrollView下物体众多时,该工具可优化drawcall。它功能完善,支持4个方向无限滚动,能自适应布局。文中还讲解了使用教程、设计思路、代码片段,最后提供了Demo工程下载链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

此篇文章当作知识学习即可,需要使用循环复用的小伙伴可以尝试博主近期开发的ScrollCircleMaker v1.0,此插件功能比较完整,使用方便,如果遇到问题可以联系我进行修改。

当ScrollView下的物体很多上百上千的时候,不可能去实例化出来这么多物体,这个时候需要优化了,不然drawcall会很大很大 ,所以笔者花了1,2天时间去写了一个比较实用的工具,那就是ScrollView无限循环滚动,接下来给大家展示一下效果(剪掉了一些帧数因为太大上传不了,实际效果更加丝滑),如下:

 自我感觉写的还是比较完善的,item样式刷新和点击事件的注册等等的基本功能,支持4个方向的无限滚动的,自适应Content大小进行布局,下面是使用的教程和设计的基本思路,最下面也将附上Demo工程的下载路径。

需要在Content下添加GridLayoutGroup,代码会读取GridLayoutGroup下的一些参数,然后会把GridLayoutGroup组件禁用掉,美术可以设置GridLayoutGroup的参数去查看无限滚动的预期效果,接下来和大家讲解一下设计的思路和一些代码的片段, 首先需要计算可显示区域行列最大值是多少,如果上下滚动的话,计算出来最大行还需要加1,这样子最大行*最大列就是需要初始化的item个数,当然需要把所有的item数据存在List<object>下用来刷新item,所以初始化这个工具类需要做这些事情,如图下:

可以看到这里还将一个函数传递进去,这个Text类是继承了ItemBase这个抽象类,一个Item将对应上一个Text的实例,实例化一个Item的时候就调用一下传递进去的委托创建一个Text实例对应上,初始化显示的时候按顺序调用ItemBase的函数,如图下:

 之后就是刷新的问题(这里就单单讲从上到下显示的刷新,其他都差不多),刷新需要先监听ScollView的拖动,所以如图下:

刷新的思路是如果向下移动的时候,第一行完全被覆盖了,这样就把第一行刷新到最下面的一行,改变位置和调用UpdaView改变Item样式,以此循环,向上刷新的时候第一行间距大于纵向间距,将最后的一行刷新到最前面的一行,接下展示一下代码的片段,如图下:

工程的下载链接:https://download.csdn.net/download/m0_37920739/11186683

### 实现 Unity ScrollView无限滚动效果 #### 1. 创建基础结构 为了创建一个高效的无限滚动 `ScrollView`,首先需要构建基本场景。这通常涉及设置一个 `Canvas` 来容纳 UI 元素,并在其内部放置一个带有 `ScrollRect` 组件的对象作为容器。 ```csharp // 设置 Canvas 和 ScrollRect 容器的基础代码片段 public GameObject canvas; public GameObject scrollRectTransform; void Start() { // 初始化 Canvas 并确保其渲染模式适合当前需求 canvas = new GameObject("Canvas", typeof(Canvas)); ((Canvas)canvas.GetComponent(typeof(Canvas))).renderMode = RenderMode.ScreenSpaceOverlay; // 创建并配置 ScrollRect 对象 scrollRectTransform = new GameObject("ScrollContainer"); RectTransform rectTransform = scrollRectTransform.AddComponent<RectTransform>(); ScrollRect scrollRectComponent = scrollRectTransform.AddComponent<ScrollRect>(); // 将 ScrollRect 添加到 Canvas 下面 scrollRectTransform.transform.SetParent(canvas.transform); } ``` #### 2. 使用自定义管理类处理数据项 对于大量条目的显示,直接实例化所有对象会导致性能下降。因此,应该采用池化技术或懒加载机制来动态生成可见区域内的项目[^2]。 ```csharp using System.Collections.Generic; public class InfiniteScroller : MonoBehaviour { private List<GameObject> itemPool; // 存储可重复使用的预制体列表 void Awake(){ itemPool = new List<GameObject>(); } public void ShowAndUpdateList(List<ItemData> dataList){ foreach (var data in dataList){ ReuseOrInstantiateItem(data); // 根据情况重用现有物品或新建 } } private void ReuseOrInstantiateItem(ItemData data){ // 查找可以被重新利用的游戏对象... var reusableItem = FindReusableItem(); if(reusableItem != null){ UpdateExistingItem(reusableItem, data); }else{ CreateNewItem(data); } } } ``` #### 3. 调整内容尺寸适应滚动行为 为了让 `ScrollView` 正确响应触摸/鼠标事件以及平滑滚动,需调整 `Content Size Fitter` 参数以匹配子元素的实际高度宽度变化[^4]。 ```csharp ContentSizeFitter fitter = contentObject.AddComponent<ContentSizeFitter>(); fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; ``` #### 4. 处理边界条件与循环逻辑 当用户接近列表末端时,应提前准备新一批待展示的数据;同样地,在顶部也需要相应操作以便形成无缝衔接的感觉。通过监听垂直位置的变化触发这些动作[^1]。 ```csharp private float lastVerticalNormalizedPosition = 0f; void LateUpdate(){ if(Math.Abs(scrollRect.normalizedPosition.y - lastVerticalNormalizedPosition) >= thresholdValue){ AdjustItemsBasedOnDirection(); // 根据方向增加新的 Item 或移除旧的 Item lastVerticalNormalizedPosition = scrollRect.normalizedPosition.y; } } private void AdjustItemsBasedOnDirection(){ bool isMovingUpward = scrollRect.velocity.y > 0 ? true : false; if(isMovingUpward && IsNearTop()){ LoadMoreAtTheBeginning(); } else if(!isMovingUpward && IsNearBottom()){ LoadMoreAtTheEnd(); } } ```
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值