Unity 中实现首尾无限循环的 ListView

article/2025/7/19 21:03:42

之前已经实现过:

Unity 中实现可复用的 ListView-CSDN博客文章浏览阅读5.6k次,点赞2次,收藏27次。源码已放入我的 github,地址:Unity-ListView前言实现一个列表组件,表现方面最核心的部分就是重写布局(Layout)。对于简单的列表,尤其是“Cell数量固定且较少、没有超页滚动展示”一类的需求,使用UGUI自带的布局组件进行布局即可。分别为:水平布局组件(Horizontal Layout Group)、竖直布局组件(Vertical Layout Gro..._unity listview https://blog.csdn.net/NRatel/article/details/100561203Unity 中实现可复用的 GridView-CSDN博客文章浏览阅读4k次。本文介绍了如何基于Unity的UGUI系统设计一个灵活的GridView组件。作者分析了GridLayoutGroup的参数,讨论了StartCorner和StartAxis的排布方式、Constraint的灵活性以及Padding与对齐方式的巧妙结合。在实现过程中,修改了ScrollRect的关联ScrollBar和布局接口,设计了适应不同滑动方向的布局,并实现了元素复用逻辑,包括四种滑动方向的计算。此外,还探讨了Content锚点、行列约束和对齐方式的调整,以提高组件的易用性。 https://blog.csdn.net/NRatel/article/details/124063559首尾无限循环 的列表,还是以 ListView 为基础。

在此之前,先参照 GrideView 修改 ListView:

使其 继承 UIScrollRect(原因是必须修改部分源码)

并支持参数:

1、MovementAxis :
        横向滑动 或 竖向滑动。

2、StartSide :
        横向滑动时,可选 元素的排列方向:从左往右 或 从右往左;
        竖向滑动时,可选 元素的排列方向:从上往下 或 从下往上。

3、ChildAligment :
        横向滑动时,可选 元素的上下对齐方式:居上/居中/居下;
        竖向滑动时,可选 元素的左右对齐方式:居左/居中/居右。

----------------------------------------- NRatel割 -----------------------------------------

Loop 首尾循环的改动要点:
(以下仅以 MovementAxis=Horizontal,StartSide=Left 的情形阐述)

先看这种情况:核心内容宽度 > viewport 宽度

1、使 Content 在移动时,非原核心内容区也能够显示 0~Count-1 范围内的 Cell元素,让越界索引不要提前retrun,而是在显示时转到 0~Count-1 之中。

如图:黑色区域为 Content, 当其继续往右滑动时,进入Viewport、但已超出 Content 的部分,仍能生成越界元素,并能将越界索引转到 界内索引之中。

需要修改 CalcIndexes,使其不要立刻拦截越界索引。而是在 DisAppearCells 和 AppearCells 时,根据 索引值判断是否越界,抽出两个方法:

//是否有效索引(只将显示索引显示到列表中,默认为 0~cellCount 之间)
//loop时,认为任意索引都是有效的,以使非 0~cellCount 的区域能够显示元素,之后再在 ConvertIndexToValid 转换
protected virtual bool IsValidIndex(int index)
{if (m_Loop) { return true; }else { return index >= 0 && index < m_CellCount; }
}
//转换索引至有效(默认无需处理)
//loop时,将任意索引数转到 [0~cellCount-1] 中
protected virtual int ConvertIndexToValid(int index)
{if (m_Loop) { return (index % m_CellCount + m_CellCount) % m_CellCount; }else { return index; }
}

处理完本条之后,理论上,将 Content的宽度设为 无限大,就可以直接支持首尾无限循环。
不过,最好还是选择位置重置的方案。

2、滑动时,从初始位置开始,只要向左/向右滑出超过1个重置单位,就将 Content 重置回起始位置。
(注意,滑动过程,完全无需考虑Cell显示问题,完全由①处理,可将Content想象为一张整图)
(注意这里说的 1个重置单位 = 1核心内容宽度 + 1个spacingX)

3、将 Content 宽度扩为原核心内容宽度扩展的N倍,使其满足位置重置的基本条件。

        支持从初始位置开始,向左向右各滑动1个重置单位,需要在两侧至少各扩展出1个重置单位。
        但为了避免 翻超1个重置单位触及边缘 触发回弹,可以额外多出1或2个重置单位。
        注意,扩宽 Content 更多倍是毫无成本的!这里只是思考至少应该扩展几倍。
        所以,直接定为 2+2=4倍。

4、再回头来思考 核心内容宽度 < viewport宽度 的倍数

        在上面的基础上,只需简单处理:将 核心内容宽度 先翻倍,使超过 viewport宽度。
        注意,这种情况下,在Viewport中会出现多个同一Cell,属于正常现象。

5、重置Content位置。但小心不能影响到 ScrollRect 内部的 速度值计算!!!

        我用了不少时间才解决这个问题。

        位置的重置,不能放在 OnScrollValueChanged。原因是:

        ①、ScrollRect 的 LateUpdate中,有逻辑为:
        开启惯性速度选项,进行拖拽时,会根据Content相邻两帧的 位置确定后续的 惯性起始速度。

        因此,如果在滑动过程中,如果只突然修改 Content 位置,将会导致 速度剧变

        ②、在 OnScrollValueChanged 修改 Content 位置过晚,将使 其他注册 OnScrollValueChanged 的地方无法获取的真实 value。

        因此,可在 SetContentAnchoredPosition 方法中,增加一个虚方法,供子类重写修改Content 的位置。

        在具体修改Content位置时,还需注意:

        ①、要同时更新 m_PrevPosition,以使本帧 LateUpdate中 计算的 m_Velocity 不会因位置剧变而剧变。

        ②、要同时更新 m_ContentStartPosition,以使 OnDrag 中,Content位置跟随鼠标移动时,不反复触发此“位置超过一页的重置逻辑”,否则下一帧 m_PrevPosition 又将执行一次偏移(上一行代码),还是会导致速度剧变。

//Content初始位置
float contentStartPosX = -m_CellStartOffsetOnMovementAxis;
//获取当前位置
float curContentPosX = m_Content.anchoredPosition.x;
//Content向左时,Content重置点坐标(初始位置左侧1个重置宽度)
float leftResetPosX = contentStartPosX - m_LoopResetSizeOnMovementAxis;
//Content向右时,Content重置点坐标(初始位置右侧1个重置宽度)
float rightResetPosX = contentStartPosX + m_LoopResetSizeOnMovementAxis;
if (curContentPosX < leftResetPosX)
{m_Content.anchoredPosition += Vector2.right * m_LoopResetSizeOnMovementAxis;//更新,以使本帧 LateUpdate中 计算的 m_Velocity 不会因位置剧变而剧变m_PrevPosition += Vector2.right * m_LoopResetSizeOnMovementAxis;//更新,以使 OnDrag 中,Content位置跟随鼠标移动时,不反复触发此“位置超过一页的重置逻辑”,否则下一帧m_PrevPosition又将执行一次偏移(上一行代码),还是会导致速度剧变m_ContentStartPosition += Vector2.right * m_LoopResetSizeOnMovementAxis;
}
else if (curContentPosX > rightResetPosX)
{m_Content.anchoredPosition += Vector2.left * m_LoopResetSizeOnMovementAxis;//更新,以使本帧 LateUpdate中 计算的 m_Velocity 不会因位置剧变而剧变m_PrevPosition += Vector2.left * m_LoopResetSizeOnMovementAxis;//更新,以使 OnDrag 中,Content位置跟随鼠标移动时,不反复触发此“位置超过一页的重置逻辑”,否则下一帧m_PrevPosition又将执行一次偏移(上一行代码),还是会导致速度剧变m_ContentStartPosition += Vector2.left * m_LoopResetSizeOnMovementAxis;
}

----------------------------------------- NRatel割 -----------------------------------------

实现效果:

源码:

https://github.com/NRatel/Unity-ListViewhttps://github.com/NRatel/Unity-ListView


http://www.hkcw.cn/article/rOHjnEoAtg.shtml

相关文章

【提升工作效率的小工具】截图软件Snipaste

1.F1截图&#xff0c;F3钉在桌面上 2.小技巧 纯文本复制后&#xff0c;F3钉在桌面上&#xff0c;鼠标右键&#xff0c;点击复制纯文本&#xff0c;可以直接再次复制 shift鼠标双击截图&#xff0c;可以缩略显示不占位置&#xff0c;重复操作就是展开截图。 隐藏/显示所有贴图…

极刻云搜2.0-强大的蓝奏搜索引擎以及智能网址导航

【&#x1f389; 重磅发布】极刻云搜 2.0 正式上线&#xff01; &#x1f680; 核心升级&#xff1a; ✨ 界面全面焕新&#xff1a; 视觉更美观&#xff0c;操作更流畅&#xff0c;体验显著提升。 &#x1f50d; 搜索能力升级&#xff1a; 在原有站内搜索&#xff08;覆盖全站…

无人机视角海上漂浮物检测与人员救援检测数据集VOC+YOLO格式2903张6类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2903 标注数量(xml文件个数)&#xff1a;2903 标注数量(txt文件个数)&#xff1a;2903 …

cocosCreator 1.8 升级到 2.4

现在负责的一个运营中的商业项目&#xff0c;使用的是 cocosCreator1.8&#xff0c;之前没有做好设计&#xff0c;所以东西都是直接加载在内存中的&#xff0c;到了现在性能问题逐渐暴露出来&#xff0c;讨论之后想进行引擎升级&#xff0c;升级到cocosCreator 2.4。 官方的升…

【递归、搜索与回溯算法】综合练习(二)

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人递归&#xff0c;搜索与回溯算法的学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码…

65.AI流式回答后再次修改同一界面的消息不在同一对话中bug

问题背景 在实现AI对话应用的流式响应功能后&#xff0c;我发现一个关键问题&#xff1a;当用户对AI的回答进行修改或重新生成时&#xff0c;有时会导致新的回答不在原对话上下文中&#xff0c;而是创建了一个新的独立对话。这种bug会严重影响用户体验和对话的连贯性。 问题现…

YOLOv8目标检测实战-(TensorRT原生API搭建网络和使用Parser搭建网络)

文章目录 一、原理篇1&#xff09;Trt基础知识2&#xff09;Trt plugin3&#xff09;int8量化算法和原理4&#xff09;cuda编程5&#xff09;onnx基础知识6&#xff09;yolov8网络架构6.1 yolov5网络架构图6.2 yolov8s网络架构 二、TensorRT原生API搭建网络1&#xff09;window…

【IC】ASIC 设计流程:什么是 ASIC 设计?

什么是 ASIC&#xff1f; ASIC&#xff08;专用集成电路&#xff09;是一种经过精心设计的专用集成电路&#xff0c;用于在电子系统中执行特定功能或功能集。与微波炉或电视盒等日常电子设备中的通用微处理器不同&#xff0c;ASIC 是为特定应用量身定制的&#xff0c;可提供无…

TKdownloader V5.5 抖音批量下载工具

目前能找到的仅存的免费抖音批量下载软件&#xff0c;有win版和mac版。 但是软件的运行需要一点点电脑知识&#xff0c;不太复杂&#xff0c;按着说明一步一步走&#xff0c;也能正常安装使用。 项目功能 下载抖音无水印视频/图集 下载抖音无水印实况/动图 下载最高画质视频文件…

Rust 编程实现猜数字游戏

文章目录 编程实现猜数字游戏游戏规则创建新项目默认代码处理用户输入代码解析 生成随机数添加依赖生成逻辑 比较猜测值与目标值类型转换 循环与错误处理优化添加循环优雅处理非法输入​ 最终完整代码核心概念总结 编程实现猜数字游戏 我们使用cargo和rust实现一个经典编程练习…

苏州SAP代理公司排名:工业园区企业推荐的服务商

目录 一、SAP实施商选择标准体系 1、行业经验维度 2、实施方法论维度 3、资质认证维度 4、团队实力维度 二、SAP苏州实施商工博科技 1、SAP双重认证&#xff0c;高等院校支持 2、以SAP ERP为核心&#xff0c;助力企业数字化转型 三、苏州使用SAP的企业 苏州是中国工业…

2505软考高项第一、二批真题终极汇总

第一批2025.05综合题&#xff08;75道选择题&#xff09; 1、2025 年中央一号文件对进一步深化农村改革的各项任务作出全面部署。“推进农业科技力量协同攻关”的相关措施不包括()。 A.强化农业科研资源力量统筹&#xff0c;培育农业科技领军企业 B.发挥农业科研平台作用&…

微深节能 堆取料机动作综合检测系统 格雷母线

精准定位&#xff0c;高效运行——微深节能格雷母线堆取料机动作综合检测系统 在现代工业自动化领域&#xff0c;精准的位置检测是保障设备高效运行的关键。武汉市微深节能科技有限公司推出的格雷母线高精度位移测量系统&#xff0c;凭借其卓越的性能和可靠性&#xff0c;成为…

Android Native 之 adbd进程分析

目录 1、adbd守护进程 2、adbd权限降级 3、adbd命令解析 1&#xff09;adb shell 2&#xff09;adb root 3&#xff09;adb reboot 4、案例 1&#xff09;案例之实现不需要执行adb root命令自动具有root权限 2&#xff09;案例之实现不需要RSA认证直接能够使用adb she…

wireshark分析国标rtp ps流

1.将抓到的tcp或者udp视频流使用decode as 转为rtp包 2.电话->RTP->RTP播放器 选择Export 里面的Payload 就可以导出原始PS流

next.js 如何做中英文切换(详解)

最近开发的项目涉及到了 react, 因为之前没用过 next.js, 发现文档比较乱&#xff0c;所以也是花了点时间&#xff0c;这里做个记录。 前提依赖&#xff1a;App 文件夹路由 {"next": "14.2.22","react-i18next": "^15.5.1","i1…

SpringAI系列4: Tool Calling 工具调用 【感觉这版本有bug】

前言&#xff1a;在最近发布的 Spring AI 1.0.0.M6 版本中&#xff0c;其中一个重大变化是 Function Calling 被废弃&#xff0c;被 Tool Calling 取代。Tool Calling工具调用&#xff08;也称为函数调用&#xff09;是AI应用中的常见模式&#xff0c;允许模型通过一组API或工具…

SAR ADC 比较器噪声分析(二)

SAR ADC的比较器是非常重要的模块&#xff0c;需要仔细设计。主要考虑比较器的以下指标&#xff1a; 1)失调电压 2)输入共模范围 3)比较器精度 4)传输延时 5)噪声 6)功耗 这里主要讲一下动态比较器的noise。 动态比较器一般用于高速SAR ADC中&#xff0c;且精度不会超过12bit…

Haproxy搭建Web集群

目录 Haproxy概述 Haproxy调度算法 静态调度算法 动态调度算法 其他调度算法 案例环境 配置网站 配置Haproxy Haproxy日志 MySQL负载均衡调度模式 Nginx负载均衡算法 Haproxy概述 Haproxy是一款开源、高性能的负载均衡和代理服务器&#xff0c;支持TCP和HTTP协议&a…

中联教育 - 嵌入式BI助力财经数据分析服务

“借助Wyn商业智能软件嵌入式BI工具强大的嵌入式能力&#xff0c;我们实现了与已有的财经教育教学实训平台的深度融合&#xff0c;大幅提升了平台的数据分析服务能力。同时&#xff0c;产品简单易用的特性&#xff0c;也让我们的学员能够快速上手&#xff0c;进行财务报表的设计…