Unity CircleLayoutGroup 如何实现一个圆形自动布局组件
文章目录
- 简介
- 实现原理
- Editor 编辑器
简介
Unity中提供了三种类型的自动布局组件,分别是Grid Layou Group
、Horizontal Layout Group
、Vertical Layout Group
,本文自定义了一个圆形的自动布局组件Circle Layout Group
,如图所示:
Radius
:Circle圆的半径Angle Delta
:两个元素之间的角度差Start Direction
:开始布局的方向(上、下、左、右)Auto Refresh
:是否自动刷新,开启后当子物体数量发生变化时自动刷新布局Control Child Size
:是否控制元素的大小Child Size
:控制元素大小
实现原理
已知圆的中心点(x0, y0),半径radius ,通过以下公式求得角度a的圆上的点坐标位置(x,y):
float x = x0 + radius * Mathf.Cos(angle * Mathf.PI / 180f);
float y = y0 + radius * Mathf.Sin(angle * Mathf.PI / 180f);
在这里我们的子物体元素以其父级为圆心,所以不需要考虑(x0,y0):
float x = radius * Mathf.Cos(angle * Mathf.PI / 180f);
float y = radius * Mathf.Sin(angle * Mathf.PI / 180f);
三角函数原理:
Sin正弦:y(对边) / radius(斜边)
Cos余弦:x(邻边)/ radius(斜边)
以右侧为0度起点,当方向为上方时加90度,当方向为左侧时加180度,当方向为下方时加270度,并根据角度差和元素的层级顺序计算其角度。
代码实现如下:
using UnityEngine;
using System.Collections.Generic;namespace SK.Framework.UI
{/// <summary>/// 圆形自动布局组件/// </summary>public class CircleLayoutGroup : MonoBehaviour{//半径[SerializeField] private float radius = 100f;//角度差[SerializeField] private float angleDelta = 30f;//开始的方向 0-Right 1-Up 2-Left 3-Down[SerializeField] private int startDirection = 0;//是否自动刷新布局[SerializeField] private bool autoRefresh = true;//是否控制子物体的大小[SerializeField] private bool controlChildSize = true;//子物体大小[SerializeField] private Vector2 childSize = Vector2.one * 100f;//缓存子物体数量private int cacheChildCount;private void Start(){cacheChildCount = transform.childCount;RefreshLayout();}private void Update(){//开启自动刷新if (autoRefresh){//检测到子物体数量变动if (cacheChildCount != transform.childCount){//刷新布局RefreshLayout();//再次缓存子物体数量cacheChildCount = transform.childCount;}} }/// <summary>/// 刷新布局/// </summary>public void RefreshLayout(){//获取所有非隐藏状态的子物体List<RectTransform> children = new List<RectTransform>();for (int i = 0; i < transform.childCount; i++){Transform child = transform.GetChild(i);if (child.gameObject.activeSelf){children.Add(child as RectTransform);}}//形成的扇形的角度 = 子物体间隙数量 * 角度差float totalAngle = (children.Count - 1) * angleDelta;//总角度的一半float halfAngle = totalAngle * 0.5f;//遍历这些子物体for (int i = 0; i < children.Count; i++){RectTransform child = children[i];/* 以右侧为0度起点 * 方向为Up时角度+90 Left+180 Down+270* 方向为Right和Up时 倒序计算角度 * 确保层级中的子物体按照从左到右、从上到下的顺序自动布局 */float angle = angleDelta * (startDirection < 2 ? children.Count - 1 - i : i) - halfAngle + startDirection * 90f;//计算x、y坐标float x = radius * Mathf.Cos(angle * Mathf.PI / 180f);float y = radius * Mathf.Sin(angle * Mathf.PI / 180f);//为子物体赋值坐标Vector2 anchorPos = child.anchoredPosition;anchorPos.x = x;anchorPos.y = y;child.anchoredPosition = anchorPos;//控制子物体大小if (controlChildSize){child.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, childSize.x);child.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, childSize.y);}}}}
}
Editor 编辑器
通过上述代码可以实现Runtime运行时的布局自动刷新,想要在Editor编辑环境编辑时自动刷新还需要自定义Editor编辑器,代码如下:
#if UNITY_EDITOR[CustomEditor(typeof(CircleLayoutGroup))]public class CircleLayoutGroupEditor : Editor{private enum Direction{Right = 0,Up = 1,Left = 2,Down = 3}private CircleLayoutGroup circleLayoutGroup;private SerializedProperty radius;private SerializedProperty angleDelta;private SerializedProperty startDirection;private SerializedProperty autoRefresh;private SerializedProperty controlChildSize;private SerializedProperty childSize;private Direction direction;private void OnEnable(){circleLayoutGroup = target as CircleLayoutGroup;radius = serializedObject.FindProperty("radius");angleDelta = serializedObject.FindProperty("angleDelta");startDirection = serializedObject.FindProperty("startDirection");autoRefresh = serializedObject.FindProperty("autoRefresh");controlChildSize = serializedObject.FindProperty("controlChildSize");childSize = serializedObject.FindProperty("childSize");direction = (Direction)startDirection.intValue;circleLayoutGroup.RefreshLayout();}public override void OnInspectorGUI(){float newRadius = EditorGUILayout.FloatField("Radius", radius.floatValue);if (newRadius != radius.floatValue){Undo.RecordObject(target, "Radius");radius.floatValue = newRadius;IsChanged();}float newAngleDelta = EditorGUILayout.FloatField("Angle Delta", angleDelta.floatValue);if (newAngleDelta != angleDelta.floatValue){Undo.RecordObject(target, "Angle Delta");angleDelta.floatValue = newAngleDelta;IsChanged();}Direction newDirection = (Direction)EditorGUILayout.EnumPopup("Start Direction", direction);if (newDirection != direction) {Undo.RecordObject(target, "Start Direction");direction = newDirection;startDirection.intValue = (int)direction;IsChanged();}bool newAutoRefresh = EditorGUILayout.Toggle("Auto Refresh", autoRefresh.boolValue);if (newAutoRefresh != autoRefresh.boolValue){Undo.RecordObject(target, "Angle Refresh");autoRefresh.boolValue = newAutoRefresh;IsChanged();}bool newControlChildSize = EditorGUILayout.Toggle("Control Child Size", controlChildSize.boolValue);if (newControlChildSize != controlChildSize.boolValue){Undo.RecordObject(target, "Control Child Size");controlChildSize.boolValue = newControlChildSize;IsChanged();}if (controlChildSize.boolValue){Vector2 newChildSize = EditorGUILayout.Vector2Field("Child Size", childSize.vector2Value);if (newChildSize != childSize.vector2Value){Undo.RecordObject(target, "Child Size");childSize.vector2Value = newChildSize;IsChanged();}}}private void IsChanged(){if (GUI.changed){serializedObject.ApplyModifiedProperties();EditorUtility.SetDirty(target);circleLayoutGroup.RefreshLayout();}}}
#endif
工具已上传SKFramework
框架Package Manager
中:
相关文章:

Unity CircleLayoutGroup 如何实现一个圆形自动布局组件
文章目录简介实现原理Editor 编辑器简介 Unity中提供了三种类型的自动布局组件,分别是Grid Layou Group、Horizontal Layout Group、Vertical Layout Group,本文自定义了一个圆形的自动布局组件Circle Layout Group,如图所示: Ra…...

springcloud+nacos+gateway案例
一、先搭建好springcloudnacos项目地址:https://javazhong.blog.csdn.net/article/details/128899999二、spring cloud gateway简述Spring Cloud Gateway 是Spring Cloud家族中的一款API网关。Gateway 建立在 Spring Webflux上,目标是提供一个简洁、高效的API网关&a…...
实习这么久,你知道Maven是如何从代码仓库中找到需要的依赖吗?
目录 碎碎念 Maven是如何找到代码仓库里需要的依赖的? 如何根据坐标在本地仓库中寻找所需要的依赖? 如何根据坐标在远程仓库中寻找所需要的依赖? Maven 如何使用 HTTP 或 HTTPS 协议从远程仓库中获取依赖项,请详细解释其原理…...

低代码/零代码的快速开发框架
目前国内主流的低代码开发平台有:宜搭、简道云、明道云、云程、氚云、伙伴云、道一云、JEPaaS、华炎魔方、搭搭云、JeecgBoot 、RuoYi等。这些平台各有优劣势,定位也不同,用户可以根据自己需求选择。 一、阿里云宜搭 宜搭是阿里巴巴集团在20…...
C# 中常见的设计模式
设计模式是一套被广泛应用于软件设计的最佳实践,它们可以帮助开发者解决特定的问题,提高代码的可重用性、可读性和可维护性。本文将介绍 C# 中常见的几种设计模式,并提供相应的示例代码。 工厂模式 工厂模式是一种创建型设计模式,…...
promethues/servicemonitor
目录 1.promethues 能保证源源不断地采集/metrics 信息吗?每次都是最新的吗 2.部署servicemonitor 的作用是什么? 3.pod 部署采集数据直接上报promthues ,不通过servicemonitor 可以吗? 4.你说的"此外,如果部署…...

postman使用简介
1、介绍 postman是一款功能强大的网页调试和模拟发送HTTP请求的Chrome插件,支持几乎所有类型的HTTP请求 2、下载及安装 官方文档:https://www.getpostman.com/docs/v6/ chrome插件:chrome浏览器应用商店直接搜索添加即可(需墙&…...
@DS注解在事务中实现数据源的切换@DS在事务中失效【已解决】
在Springboot的application.yml中的配置: spring:datasource:url: jdbc:mysql://localhost:3306/test2?serverTimezoneUTC&useUnicodetrue&characterEncodingutf8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rootdynamic:primar…...
Java I/O之文件系统
一、全文概览 在学习文件系统之前,需要了解下Java在I/O上的发展史:在Java7之前,打开和读取文件需要编写特别笨拙的代码,涉及到很多的InputStream、OutputStream等组合起来使用,每次在使用时或许都需要查一下文档才能记…...

Mysql元数据获取方法(information_schema绕过方法)
前提:如果waf或其它过滤了information_schema关键字,那我们该如何获取元数据呢?能够代替information_schema的有:sys.schema_auto_increment_columnssys.schema_table_statistics_with_bufferx$schema_table_statistics_with_buff…...
Eclipse快捷键
* 1.补全代码的声明:alt /* 2.快速修复: ctrl 1 * 3.批量导包:ctrl shift o* 4.使用单行注释:ctrl /* 5.使用多行注释: ctrl shift / * 6.取消多行注释:ctrl shift \* 7.复制指定行的代码:ctrl a…...

java ssm自习室选座预约系统开发springmvc
人工管理显然已无法应对时代的变化,而自习室选座预约系统开发能很好地解决这一问题,既能提高人力物力,又能提高预约选座的知名度,取代人工管理是必然趋势。 本自习室选座预约系统开发以SSM作为框架,JSP技术,…...

分享我从功能测试转型到测试开发的真实故事
由于这段时间我面试了很多家公司,也经历了之前公司的不愉快。所以我想写一篇文章来分享一下自己的面试体会。希望能对我在之后的工作或者面试中有一些帮助,也希望能帮助到正在找工作的你。 找工作 我们总是草率地进入一个自己不了解的公司工作…...

TypeScript快速入门———(二)TypeScript常用类型
文章目录概述1 类型注解2 常用基础类型概述3.原始类型4 数组类型5 类型别名6.函数类型7 对象类型8 接口9 元组10 类型推论11 类型断言12 字面量类型13 枚举14 any 类型15 typeof概述 TypeScript 是 JS 的超集,TS 提供了 JS 的所有功能,并且额外的增加了…...

Mac M1 使用Centos8➕VMware Fusion进行静态网络配置
大部分的流程网络上面都有当我们已经下载好mac m1版的Centos8链接: https://pan.baidu.com/s/1UTl4Lo-_c17s-PDj3dA6kA 提取码: 7xh2 和VMware Fusionhttps://www.vmware.com/cn/products/fusion.html之后就可以进行安装了在导入过后 记得将硬盘和内存都设置好了 记得在关机状态…...

RadGraph: Extracting Clinical Entities and Relations from Radiology Reports代码
文章来源:NeurIPS 文章类别:IE(Information Extraction) RadGraph主要基于dygie,主要文件为inference.py。 inference.py: 1、get_file_list(data_path) def get_file_list(path):file_list [item for item in glob.glob(f&q…...
13. OPenGL与QT界面元素交互控制图形渲染
1. 说明: 前面文章中讲到的 OPenGL 渲染都是在页面加载完成即立刻渲染的,如果向控制图形渲染的时间,可以在QT界面中添加一些元素来进行控制。此时需要用到OPenGL当中的makeCurrent(),update(),doneCurrent()函数。 效果展示: ope…...

高通平台开发系列讲解(USB篇)libuvc详解
文章目录 一、什么是UVC二、UVC拓扑结构三、libuvc的预览时序图沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇文章将介绍libuvc。 一、什么是UVC UVC,全称为:USB video(device) class。 UVC是微软与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标…...
ICC2:set_route_opt_target_endpoints
route_opt阶段通过指定endpoint/driver pin list的方式执行incremental优化。 set_route_opt_target_endpoints [-setup_endpoints file] [-setup_endpoints_collection pin_list] [-hold_endpoints file] [-hold_endpoints_collection pin_list] [-ldrc_objects fil…...
5、小程序面试题
1, 小程序页面有哪些生命周期函数onLoad: 页面加载onReady: 页面初次渲染完成onShow: 页面显示onHide: 页面隐藏onUnload: 页面卸载2, 一页小程序页面有哪些文件组成,分别有什么作用.wxml: 使用微信框架设计的一套组件构建页面结构.wxss: 用于设置页面样式, 和css基本一致.js :…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...