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在此新建的文件夹路径下,包含子文件夹内的…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...