Unity 圆形循环复用滚动列表
一.在上一篇垂直循环复用滚动列表的基础上,扩展延申了圆形循环复用滚动列表。实现此效果需要导入垂直循环复用滚动列表里面的类。
1.基础类
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.UIElements;/// <summary>
/// 环形的网格布局;
/// 让子对象摆成一个环形;
/// </summary>
public class CricleGrid : MonoBehaviour
{/// <summary>/// 是否是自动刷新模式,否则的话需要手动调用刷新;/// </summary>public bool IsAutoRefresh = true;/// <summary>/// 是否发生过改变;/// </summary>private bool IsChanged = false;/// <summary>/// 上一次检查的数量;/// </summary>int LastCheckCount = 0;/// <summary>/// Update每帧调用一次/// </summary>void Update(){检查是否需要自动刷新;if (!IsAutoRefresh)return;if (!IsChanged){//检测子物体有没有被改变;GetChidList();int length = ListRect.Count;if (length != LastCheckCount){LastCheckCount = length;IsChanged = true;}//此时刷新大小和位置;if (IsChanged)ResetSizeAndPos();}elseRefreshAll();}private void OnValidate(){//编辑器下每一次更改需要实时刷新;RefreshAll();}/// <summary>/// 全部刷新;/// </summary>public void RefreshAll(){GetChidList();ResetSizeAndPos();}/// <summary>/// 当下激活的Rect;/// </summary>public List<RectTransform> ListRect = new List<RectTransform>(4);List<RectTransform> tempListRect = new List<RectTransform>(4);/// <summary>/// 获取父节点为本身的子对象/// </summary>void GetChidList(){ListRect.Clear();GetComponentsInChildren(false, tempListRect);int length = tempListRect.Count;for (int i = 0; i < length; i++){var r = tempListRect[i];if (r.transform.parent != transform) continue;ListRect.Add(r);}}/// <summary>/// 网格大小;/// </summary>public Vector2 CellSize = new Vector2();/// <summary>/// 半径;/// </summary>public float Radius = 1;/// <summary>/// 起始角度;/// </summary>[Range(0f, 360f)][SerializeField]float m_StartAngle = 30;/// <summary>/// 起始角度;/// </summary>public float StartAngle{get { return m_StartAngle; }set{m_StartAngle = value;IsChanged = true;}}/// <summary>/// 间隔角度;/// </summary>[Range(0f, 360f)][SerializeField]float m_Angle = 30;/// <summary>/// 间隔角度;/// </summary>public float Angle{get { return m_Angle; }set{m_Angle = value;IsChanged = true;}}public Dictionary<int, CricleScrollItemPosData> itemPosDic = new();public List<CricleScrollItemPosData> itemPosList = new();/// <summary>/// 重新将字节点设置大小;/// </summary>public void ResetSizeAndPos(){int length = ListRect.Count;for (int i = 0; i < length; i++){var tran = ListRect[i];tran.sizeDelta = CellSize;var v = GerCurPosByIndex(i);tran.anchoredPosition = new Vector2(v.x,v.y);tran.localEulerAngles = new Vector3(0,0, v.z);}}/// <summary>/// 返回第几个子对象应该所在的相对位置;/// </summary>public Vector3 GerCurPosByIndex(int index){//1、先计算间隔角度:(弧度制)float totalAngle = Mathf.Deg2Rad * (index * Angle + m_StartAngle);//2、计算位置Vector3 Pos = new Vector2(Radius * Mathf.Cos(totalAngle), Mathf.Sin(totalAngle) * Radius);Pos.z = index * Angle + m_StartAngle + 180;return Pos;}public ScrollRect scrollRect;public List<object> list = new();public GameObject item;private List<CustomScrollItemMono> scrollTestItems = new();private int startIndex;private int endIndex;private int showItemCount = 10;private void InitItemsPos() {int n = (int)(360f / Angle);for (int i = 0; i < list.Count; i++){var v = GerCurPosByIndex(i);CricleScrollItemPosData data = new CricleScrollItemPosData();data.AnchoredPosition = new Vector3(v.x, v.y);data.LocalEulerAngles = new Vector3(0, 0, v.z);itemPosDic.Add(i, data);itemPosList.Add(data);//if (i < n)//{// var v = GerCurPosByIndex(i);// CricleScrollItemPosData data = new CricleScrollItemPosData();// data.AnchoredPosition = new Vector3(v.x, v.y);// data.LocalEulerAngles = new Vector3(0, 0, v.z);// itemPosDic.Add(i, data);// itemPosList.Add(data);//}//else //{// int temp = i % n;// int m = (i + 1) / n;// CricleScrollItemPosData d = new CricleScrollItemPosData();// d.AnchoredPosition = itemPosDic[temp].AnchoredPosition;// d.LocalEulerAngles.z += itemPosDic[temp].LocalEulerAngles.z + 360 * m;// itemPosDic.Add(i, d);// itemPosList.Add(d);//}}Debug.Log($"InitItemsPos ");}private void InitShowItems(){for (int i = 0; i < showItemCount; i++){GameObject obj = Instantiate(item, transform);obj.transform.name = i.ToString();obj.SetActive(true);CustomScrollItemMono testItem = obj.GetComponent<CustomScrollItemMono>();testItem.Init(i, list[i]);scrollTestItems.Add(testItem);}item.SetActive(false);}private float eulerAnglersZ;private float preA = 1;public ScrollRect ScrollRect;private RectTransform Content;/// <summary>/// 用这个初始化/// </summary>void Start(){for (int i = 0; i < 100; i++){list.Add(new ScrollTestData() { ID = i });}Content = ScrollRect.content;Content.sizeDelta = new Vector2(500, (100 * Angle / 360 + StartAngle % 360 / 360f) * 2 * Mathf.PI * Radius);InitItemsPos();InitShowItems();RefreshAll();}private void Awake(){scrollRect.horizontal = false;scrollRect.vertical = true;scrollRect.onValueChanged.AddListener((value) =>{float offset = Mathf.Abs(preA - value.y);float aa = (offset) * ((100 - 6) * Angle);if (scrollRect.velocity.y > 0) //手指上滑 {transform.localEulerAngles -= new Vector3(0,0, aa);eulerAnglersZ += aa;}else if (scrollRect.velocity.y < 0)//手指下滑 {transform.localEulerAngles += new Vector3(0, 0, aa);eulerAnglersZ -= aa;}preA = value.y;for (int i = startIndex; i < itemPosList.Count; i++){if (i + 1 < itemPosList.Count){if (scrollRect.velocity.y > 0)//手指上滑 {var targetY = itemPosList[i + 1].LocalEulerAngles.z - 180;//Debug.Log($"ccc y {y} targetY {targetY} startIndex {startIndex} Z {transform.localEulerAngles.z}");if (eulerAnglersZ + StartAngle >= targetY){startIndex = i + 1;endIndex = startIndex + showItemCount - 1;break;}}else if (scrollRect.velocity.y < 0)//手指下滑{if (startIndex > 0 && startIndex < itemPosDic.Count){var targetY = itemPosDic[startIndex].LocalEulerAngles.z - 180;if (eulerAnglersZ + StartAngle <= targetY){startIndex = i - 1;endIndex = startIndex + showItemCount - 1;break;}}}}}//Debug.Log($"bbb startIndex {startIndex} endIndex {endIndex}");if (startIndex > 100 - showItemCount) {startIndex = 100 - showItemCount;}if (endIndex >= itemPosDic.Count) { return; }int index = 0;for (int i = startIndex; i < endIndex + 1; i++){if (index < scrollTestItems.Count && i < itemPosDic.Count){var item = scrollTestItems[index];item.Init(i, list[i]);var rect = item.gameObject.GetComponent<RectTransform>();rect.anchoredPosition3D = itemPosDic[i].AnchoredPosition;rect.localEulerAngles = itemPosDic[i].LocalEulerAngles;index += 1;}}});}public class CricleScrollItemPosData{public Vector3 AnchoredPosition;public Vector3 LocalEulerAngles;}}
2.UI目录



3.item克隆体,挂载脚本

4.按照图示,把CricleGrid脚本,挂在Items节点下,调整各个参数,运行即可。
相关文章:
Unity 圆形循环复用滚动列表
一.在上一篇垂直循环复用滚动列表的基础上,扩展延申了圆形循环复用滚动列表。实现此效果需要导入垂直循环复用滚动列表里面的类。 1.基础类 using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using …...
聚水潭数据无缝集成到金蝶云星空的实现方案
聚水潭数据集成到金蝶云星空:聚水潭调拨对接金蝶直接调拨ok 在企业信息化管理中,数据的高效流动和准确对接是实现业务流程顺畅运行的关键。本文将分享一个具体的系统对接集成案例——如何通过轻易云数据集成平台,将聚水潭的数据无缝集成到金…...
虚拟机断网没有网络,需清理内存,删除后再重启
进入NetworkManager可能没权限,设置权限777 to...
[c++11(二)]Lambda表达式和Function包装器及bind函数
1.前言 Lambda表达式着重解决的是在某种场景下使用仿函数困难的问题,而function着重解决的是函数指针的问题,它能够将其简单化。 本章重点: 本章将着重讲解lambda表达式的规则和使用场景,以及function的使用场景及bind函数的相关使…...
基于字节大模型的论文翻译(含免费源码)
基于字节大模型的论文翻译 源代码: 👏 star ✨ https://github.com/boots-coder/LLM-application 展示 项目简介 本项目是一个基于大语言模型(Large Language Model, LLM)的论文阅读与翻译辅助工具。它通过用户界面(…...
Mysql语法之DQL查询的多行函数
Mysql的多行函数和分组 目录 Mysql的多行函数和分组多行函数概念常用的多行函数 数据分组概念语法where和having的区别 语句关键字及执行顺序语句关键字执行顺序 实际操作基本语句格式和多行操作筛选语句格式 多行函数 概念 不管函数处理多少条,只返回一条记录&…...
OpenSSL 心脏滴血漏洞(CVE-2014-0160)
OpenSSL 心脏滴血漏洞(CVE-2014-0160) Openssl简介: 该漏洞在国内被译为"OpenSSL心脏出血漏洞”,因其破坏性之大和影响的范围之广,堪称网络安全里程碑事件。 OpenSSL心脏滴血漏洞的大概原理是OpenSSL在2年前引入了心跳(hearbea0机制来维特TS链接的…...
监控视频汇聚融合云平台一站式解决视频资源管理痛点
随着5G技术的广泛应用,各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据,并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而,随着数字化建设和生产经营管理活动的长期开展࿰…...
ElasticSearch 数据同步
1、同步调用 操作步骤: 管理系统新增酒店数据添加到数据库调用 ES 更新文档接口,同步数据库的数据到 ES 文档 流程图: 特点: 优点:实现简单,粗暴缺点:业务耦合度高 2、异步消息通知 操作步骤…...
MyBatis-Plus中isNull与SQL语法详解:处理空值的正确姿势
目录 前言1. 探讨2. 基本知识3. 总结 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读: java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全&#x…...
RabbitMQ个人理解与基本使用
目录 一. 作用: 二. RabbitMQ的5中队列模式: 1. 简单模式 2. Work模式 3. 发布/订阅模式 4. 路由模式 5. 主题模式 三. 消息持久化: 消息过期时间 ACK应答 四. 同步接收和异步接收: 应用场景 五. 基本使用 ÿ…...
Python球球大作战
系列文章 序号直达链接表白系列1Python制作一个无法拒绝的表白界面2Python满屏飘字表白代码3Python无限弹窗满屏表白代码4Python李峋同款可写字版跳动的爱心5Python流星雨代码6Python漂浮爱心代码7Python爱心光波代码8Python普通的玫瑰花代码9Python炫酷的玫瑰花代码10Python多…...
入侵他人电脑,实现远程控制(待补充)
待补充 在获取他人无线网网络密码后,进一步的操作是实现入侵他人电脑,这一步需要获取对方的IP地址并需要制作自己的代码工具自动化的开启或者打开对方的远程访问权限。 1、获取IP地址(通过伪造的网页、伪造的Windows窗口、hook,信…...
数据分析实战—IMDB电影数据分析
1.实战内容 1.加载数据到movies_df,输出前5行,输出movies_df.info(),movies_df.describe() # (1)加载数据集,输出前5行 #导入库 import pandas as pd import numpy as np import matplotlib import matplotlib.pyplo…...
Google guava 最佳实践 学习指南之08 `BiMap`(双向映射)
guava 最佳实践 学习指南 Google Guava 库中的 BiMap(双向映射)是一种特殊的映射类型,它维护了映射的反向视图,并确保不存在重复值,且始终可以安全地使用值获取对应的键。以下是关于 Guava BiMap 的一些介绍和用法&am…...
【设计模式】空接口
(空)接口的用法总结 接口用于定义某个类的特定能力或特性。在工作流或任务管理系统中,接口可以帮助标识哪些任务可以在特定阶段执行。通过实现这些接口,任务类可以被标识为在相应的阶段可以执行,从而在验证和执行逻辑…...
Grad-CAM-解释CNN决策过程的可视化技术
Grad-CAM(Gradient-weighted Class Activation Mapping)是一种用于解释卷积神经网络(CNN)决策过程的可视化技术。其核心思想是通过计算分类分数相对于网络确定的卷积特征的梯度,来识别图像中哪些部分对分类结果最为重要…...
前后端学习中本周遇到的内容
一、RequiresPermissions注解 例如: RequiresPermissions("demo:staff:save") void saveStaff(); 权限控制,要求含有demo:staff:save的权限才能执行方法saveStaff()。 二、遇到的细节问题 在进行增删改查时,发送http请求时&…...
基于海思soc的智能产品开发(巧用mcu芯片)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 对于开发车规级嵌入式软件的同学来说,socmcu这样的组合,他们并不陌生。但是传统的工业领域,比如发动机、医疗或…...
批量DWG文件转dxf(CAD图转dxf)——c#插件实现
此插件可将指定文件夹及子文件夹下的dwg文件批量转为dxf文件。 (使用方法:命令行输入 “netload” 加载插件,然后输入“dwg2dxf”运行,选择文件夹即可。) 生成dxf在此新建的文件夹路径下,包含子文件夹内的…...
手机号定位终极指南:3分钟掌握号码背后的位置秘密
手机号定位终极指南:3分钟掌握号码背后的位置秘密 【免费下载链接】location-to-phone-number This a project to search a location of a specified phone number, and locate the map to the phone number location. 项目地址: https://gitcode.com/gh_mirrors/…...
MAI-UI-8B在Ubuntu系统中的性能优化指南
MAI-UI-8B在Ubuntu系统中的性能优化指南 1. 引言 如果你正在Ubuntu系统上运行MAI-UI-8B模型,可能会遇到性能瓶颈问题。模型响应慢、资源占用高、推理速度不理想,这些都是实际使用中常见的痛点。作为一名技术从业者,我深知这些性能问题对开发…...
需求分析避坑指南:如何避免‘用户说要马实际要车’的经典陷阱?
需求分析避坑指南:如何避免‘用户说要马实际要车’的经典陷阱? 在软件开发领域,需求分析是项目成败的关键环节。据统计,约70%的项目失败源于需求不明确或理解偏差。当用户说"想要一匹更快的马"时,他们真正需…...
突破难关:AI专著撰写工具应用技巧,助你快速著书立说
学术专著写作困境与AI工具的崛起 对许多研究人员来说,撰写学术专著最大的挑战,就是“有限的精力”与“无尽的需求”之间的矛盾。专著的写作过程通常需要三到五年,甚至更长的时间,而研究者们在日常工作中还要应对教学、研究项目和…...
构建高性能语音识别API:FastAPI与Whisper实战指南 [特殊字符]
构建高性能语音识别API:FastAPI与Whisper实战指南 🚀 【免费下载链接】awesome-fastapi A curated list of awesome things related to FastAPI 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-fastapi 在当今人工智能和语音技术飞速发展的…...
从振荡器到稳定电源:用三阶RC滤波电路讲透控制环路的‘稳定’与‘发散’
从振荡器到稳定电源:三阶RC滤波电路揭示控制环路的稳定性本质 想象一下,你正在调试一个看似简单的三阶RC低通滤波电路。当你逐渐增大放大器的增益时,电路突然从安静的滤波状态转变为持续振荡——原本应该衰减高频信号的电路,现在…...
为什么你的LoRA微调总在step 217崩溃?Python大模型调试日志解密:从`torch._C._debug_dump_tracing_state()`到生产级可观测性
第一章:LoRA微调崩溃现象的系统性认知LoRA(Low-Rank Adaptation)作为一种高效参数微调技术,虽显著降低显存开销与训练成本,但在实际落地过程中频繁出现训练过程突然中断、梯度爆炸、loss突变为NaN或GPU内存溢出等“崩溃…...
用Python脚本自动化Mininet拓扑测试:3个提升SDN实验效率的技巧
Python脚本自动化Mininet拓扑测试:3个提升SDN实验效率的技巧 在软件定义网络(SDN)的研究与开发中,Mininet作为轻量级网络仿真工具已成为行业标准。然而,随着实验复杂度的提升,手动配置拓扑和流表的方式往往…...
Python实战:用NumPy实现酉矩阵的生成与验证(附完整代码)
Python实战:用NumPy实现酉矩阵的生成与验证(附完整代码) 在量子计算、信号处理和机器学习等领域,复数矩阵运算正变得越来越重要。酉矩阵(Unitary Matrix)作为复数域上的"正交矩阵",保…...
开源工具管理效率提升使用指南
开源工具管理效率提升使用指南 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-launcher 开源工具管理…...
