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在此新建的文件夹路径下,包含子文件夹内的…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
