当前位置: 首页 > news >正文

Unity自定义数组在Inspector窗口的显示方式

了解

  1. 单行高度:EditorGUIUtility.singleLineHeight
  2. 获取 PropertyField 控件所需的高度:EditorGUI.GetPropertyHeight
  3. 属性是否在Inspector窗口展开:SerializedProperty.isExpanded
  4. 可重新排序列表类:ReorderableList
  5. 绘制纯色矩形:EditorGUI.DrawRect

示例

使用版本:2021.3.6f1c1
此版本的Unity已经实现数组元素添加,移除,移动功能。

自定义类

[System.Serializable]
public class Test 
{public string name;public int age;
}

数据类

定义一个数组,数组元素为自定义类

using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu]
public class TestSO : ScriptableObject
{public List<Test> testList;
}

数据类文件默认显示如下

在这里插入图片描述

修改数据类显示

数据元素内容显示为一行

注意:不能使用自动布局api

using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(Test))]
public class TestDrawer : PropertyDrawer
{public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){var spName = property.FindPropertyRelative("name");var spAge = property.FindPropertyRelative("age");var rect1 = position;var rect2 = position;var indentlevel = EditorGUI.indentLevel;var lableWidth = EditorGUIUtility.labelWidth;EditorGUI.indentLevel = 2;EditorGUIUtility.labelWidth = 60;rect1.width = position.width / 2;rect1.height = EditorGUIUtility.singleLineHeight;rect2.width = position.width / 2;rect2.height = EditorGUIUtility.singleLineHeight;rect2.x = position.width / 2+40;rect2.y = rect1.y;EditorGUI.PropertyField(rect1, spName, new GUIContent("名字"));EditorGUI.PropertyField(rect2, spAge, new GUIContent("年龄"));EditorGUI.indentLevel = indentlevel;EditorGUIUtility.labelWidth = lableWidth;//EditorGUI.DrawRect(rect1, Color.green);//EditorGUI.DrawRect(rect2, Color.gray);}//获取属性高度public override float GetPropertyHeight(SerializedProperty property, GUIContent label){return base.GetPropertyHeight(property, label);}
}

修改后显示效果如下图所示
在这里插入图片描述

TestList修改为指定名称;Element修改为指定名称

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(TestSO))]
public class TestSOEditor : Editor
{SerializedProperty sPTestList;ReorderableList arrayList;private void OnEnable(){sPTestList = serializedObject.FindProperty("testList");if (arrayList == null){arrayList = new ReorderableList(serializedObject, sPTestList, true, true, true, true);    //绘制HeaderarrayList.drawHeaderCallback += DrawHeader;//绘制数组元素arrayList.drawElementCallback += DrawElement;//获取数组的高度arrayList.elementHeightCallback += DrawElementHeight;}}void DrawHeader(Rect rect){EditorGUI.LabelField(rect, "测试列表");}void DrawElement(Rect rect, int index, bool isActive, bool isFocused){var element = sPTestList.GetArrayElementAtIndex(index);var arrowRect = rect;int indentLevel = EditorGUI.indentLevel;EditorGUI.indentLevel = 1;arrowRect.height = EditorGUIUtility.singleLineHeight;element.isExpanded = EditorGUI.Foldout(arrowRect, element.isExpanded, new GUIContent("元素" + index));EditorGUI.indentLevel = indentLevel;//EditorGUI.DrawRect(rect, Color.red);//EditorGUI.DrawRect(arrowRect, Color.blue);if (element.isExpanded){rect.y += arrowRect.height;EditorGUI.PropertyField(rect, element);}}float DrawElementHeight(int index){var element = sPTestList.GetArrayElementAtIndex(index);var height = EditorGUIUtility.singleLineHeight;//折叠箭头的高度   if (element.isExpanded)//如果元素展开 获取展开内容的高度和箭头的高度之和height += EditorGUI.GetPropertyHeight(element);return height;}public override void OnInspectorGUI(){serializedObject.Update();arrayList.DoLayoutList();serializedObject.ApplyModifiedProperties();}
}

修改后如下图所示
在这里插入图片描述

示例二

高度计算放在PropertyDrawer的OnGUI中

自定义类

显示折叠箭头,数据元素内容显示为一行,Element修改为指定名称

using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(Test))]
public class TestDrawer : PropertyDrawer
{public override void OnGUI(Rect position, SerializedProperty property, GUIContent label){var spName = property.FindPropertyRelative("name");var spAge = property.FindPropertyRelative("age");var rect0 = position;rect0.height = EditorGUIUtility.singleLineHeight;var indentlevel = EditorGUI.indentLevel;EditorGUI.indentLevel = 1;property.isExpanded = EditorGUI.Foldout(rect0, property.isExpanded, label);EditorGUI.indentLevel = indentlevel;if (property.isExpanded){var rect1 = position;var rect2 = position;indentlevel = EditorGUI.indentLevel;var lableWidth = EditorGUIUtility.labelWidth;EditorGUI.indentLevel = 2;EditorGUIUtility.labelWidth = 60;rect1.width = position.width / 2;rect1.height = EditorGUIUtility.singleLineHeight;rect1.y += EditorGUIUtility.singleLineHeight;rect2.width = position.width / 2;rect2.height = EditorGUIUtility.singleLineHeight;rect2.x = position.width / 2 + 40;rect2.y = rect1.y;EditorGUI.PropertyField(rect1, spName, new GUIContent("名字"));EditorGUI.PropertyField(rect2, spAge, new GUIContent("年龄"));EditorGUI.indentLevel = indentlevel;EditorGUIUtility.labelWidth = lableWidth;//EditorGUI.DrawRect(rect1, Color.green);//EditorGUI.DrawRect(rect2, Color.gray);}}public override float GetPropertyHeight(SerializedProperty property, GUIContent label){if (property.isExpanded)return EditorGUIUtility.singleLineHeight * 2;elsereturn EditorGUIUtility.singleLineHeight;}
}

数据类

TestList修改为指定名称

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(TestSO))]
public class TestSOEditor : Editor
{SerializedProperty sPTestList;ReorderableList arrayList;private void OnEnable(){sPTestList = serializedObject.FindProperty("testList");if (arrayList == null){arrayList = new ReorderableList(serializedObject, sPTestList, true, true, true, true);//绘制HeaderarrayList.drawHeaderCallback += DrawHeader;//绘制数组元素arrayList.drawElementCallback += DrawElement;//绘制元素高度arrayList.elementHeightCallback += DrawHeight;void DrawHeader(Rect rect){EditorGUI.LabelField(rect, "测试列表");}void DrawElement(Rect rect, int index, bool isActive, bool isFocused){//参数会传递给PropertyDrawer的OnGUI EditorGUI.PropertyField(rect, sPTestList.GetArrayElementAtIndex(index), new GUIContent("元素 " + index));}float DrawHeight(int index){return EditorGUI.GetPropertyHeight(sPTestList.GetArrayElementAtIndex(index));}}}public override void OnInspectorGUI(){serializedObject.Update();arrayList.DoLayoutList();serializedObject.ApplyModifiedProperties();}
}

参考

看完后理解列表的高度如何计算

相关文章:

Unity自定义数组在Inspector窗口的显示方式

了解 单行高度:EditorGUIUtility.singleLineHeight获取 PropertyField 控件所需的高度:EditorGUI.GetPropertyHeight属性是否在Inspector窗口展开&#xff1a;SerializedProperty.isExpanded可重新排序列表类&#xff1a;ReorderableList绘制纯色矩形&#xff1a;EditorGUI.Dr…...

ERC论文阅读(03)--SPCL论文阅读笔记(2024-10-29)

SPCL论文阅读笔记 论文中心思想 这篇论文是研究ERC任务的论文&#xff0c;作者提出了监督原型对比学习的方法用于ERC任务。 论文 EMNLP2022 paper “Supervised Prototypical Contrastive Learning for Emotion Recognition in Conversation” 现存问题 现存的使用监督对…...

Straightforward Layer-wise Pruning for More Efficient Visual Adaptation

对于模型中冗余的参数&#xff0c;一个常见的方法是通过结构化剪枝方法减少参数容量。例如&#xff0c;基于幅度值和基于梯度的剪枝方法。尽管这些方法在传统训练上通用性&#xff0c;本文关注的PETL迁移有两个不可避免的问题&#xff1a; 显著增加了模型存储负担。由于不同的…...

喜讯 | 创邻科技杭州电子科技大学联合实验室揭牌成立!

近日&#xff0c;杭州电子科技大学图书情报专业硕士行业导师聘任仪式暨杭电-创邻图技术与数字化联合实验室&#xff08;图书档案文物数字云联合研发中心&#xff09;揭牌仪式在杭州电子科技大学隆重举行。杭州电子科技大学原副校长吕金海、研究生院副院长潘建江&#xff0c;科研…...

海外媒体发稿:如何打造媒体发稿策略

新闻媒体的发稿推广策略对于提升品牌知名度、吸引流量以及增加收入非常重要。本文将介绍一套在21天内打造爆款新闻媒体发稿推广策略的方法。 第一天至第七天&#xff1a;明确目标和定位 在这个阶段&#xff0c;你需要明确你的目标和定位&#xff0c;以便为你的新闻媒体建立一个…...

PyTorch模型保存与加载

1.保存与加载的概念(序列化与反序列化) 模型训练完毕之后,肯定想要把它保存下来,供以后使用,不需要再次去训练。 那么在pytorch中如何把训练好的模型,保存,保存之后又如何加载呢? 这就用需要序列化与反序列化,序列化与反序列化的概念如下图所示: 因为在内…...

CH569开发前的测试

为了玩转准备Ch569的开发工作 &#xff0c;准备了如下硬件和软件&#xff1a; 硬件 1.官方的 Ch569 开发板&#xff0c;官方买到的是两块插接在一起的&#xff1b;除了HSPI接口那里的电阻&#xff0c;这两块可以说是一样的。也意味着两块板子的开发也需要烧录两次&#xff1b…...

MySQL中表的外连接和内连接

内连接和外连接 ​ 表的连接分为内连接和外连接&#xff0c;内连接就是将需要连接的表形成笛卡尔积筛选&#xff1b;外连接分为左外连接和右外连接&#xff0c;左外连接为左侧的表需要完全显示&#xff0c;右外连接为右侧的表现需要完全显示。 文章目录 内连接和外连接内连接外…...

Ubuntu 上安装 Redmine 5.1 指南

文章目录 官网安装文档&#xff1a;命令步骤相关介绍GemRubyRailsBundler 安装 Redmine更新系统包列表和软件包&#xff1a;安装必要的依赖&#xff1a;安装 Ruby&#xff1a;安装 bundler下载 Redmine 源代码&#xff1a;安装 MySQL配置 Redmine 的数据库配置文件&#xff1a;…...

从变量的角度理解 Hooks , 变得更简单了

从变量角度理解Hooks 在React的世界里&#xff0c;Hooks的引入为函数式组件带来了前所未有的灵活性和能力。它们让我们得以完全摆脱class式的写法&#xff0c;在函数式组件中完成生命周期管理、状态管理、逻辑复用等几乎全部组件开发工作。这次&#xff0c;我们就从变量的角度…...

LabVIEW Modbus通讯稳定性提升

在LabVIEW开发Modbus通讯程序时&#xff0c;通讯不稳定是一个常见问题&#xff0c;可能导致数据丢失、延迟或错误。为了确保通讯的可靠性&#xff0c;可以从多个角度进行优化&#xff0c;以下是一些有效的解决方案&#xff0c;结合实际案例进行分析。 1. 优化通讯参数设置 通讯…...

(8) cuda分析工具

文章目录 Nvidia GPU性能分析工具Nsight SystemNvidia GPU性能分析工具Nsight System Nvidia GPU性能分析工具Nsight System NVIDIA Nsight Systems是一个系统级的性能分析工具&#xff0c;用于分析和优化整个CUDA应用程序或系统的性能。它可以提供对应用程序整体性能的全面见…...

C语言 | Leetcode C语言题解之第517题超级洗衣机

题目&#xff1a; 题解&#xff1a; int findMinMoves(int* machines, int machinesSize){int sum0;for(int i0;i<machinesSize;i){summachines[i];}if(sum%machinesSize!0){return -1;}int psum/machinesSize;int ans0;int cur0;for(int i0;i<machinesSize;i){cur(mac…...

Java多线程编程基础

目录 编写第一个多线程程序 1. 方式一 : 继承Thread类, 重写run方法 2. 方式二: 实现Runnable接口, 重写run方法 3. 方式三: 使用Lambda表达式 [匿名内部类] [Lambda表达式] 在上个文章中, 我们了解了进程和线程的相关概念. 那么, 在Java中, 我们如何进行多线程编程呢? …...

刷代随有感(134):单调栈——下一个更大元素I(难点涉及哈希表与单调栈的结合)

单调栈处理的是下标&#xff01; 题干&#xff1a; 代码&#xff1a; class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {stack<int>ddst;unordered_map<int,int>umap;vector<int…...

Linux云计算 |【第五阶段】CLOUD-DAY5

主要内容&#xff1a; 容器的镜像编排&#xff0c;commit简单镜像创建&#xff0c;Dockerfile制作服务镜像&#xff08;语法、创建镜像&#xff09;、创建复杂镜像&#xff08;Docker微服务架构、示例&#xff1a;NGINXPHP&#xff09;、私有仓库 一、简单镜像创建 1、自定义…...

被上传文件于后端的命名策略

上一篇博客我们了解了前端上传的文件资源应该存放在后端项目中的什么位置&#xff0c;那么随之而来的另一个问题——我们应该如何为上传的文件命名呢&#xff1f;往往直接采用原文件名并不稳妥&#xff0c;会导致命名冲突、文件冲突、数据库管理冲突等多种问题&#xff0c;下面…...

哈希表 算法专题

哈希表简介 是什么 存储数据的容器有啥用? "快速"查找某个元素什么时候用哈希表 频繁地查找某个数(有序用二分)怎么用哈希表 容器用数组模拟 字符串中的字符 范围比较小的数 一. 两数之和 两数之和 class Solution {public int[] twoSum(int[] nums, int targe…...

unity3d————[HideInInspector]

在Unity3D中&#xff0c;[HideInInspector]是一个属性修饰符&#xff0c;它的主要作用是在Unity的Inspector窗口中隐藏变量或属性。以下是关于[HideInInspector]的详细解释和作用&#xff1a; 作用 隐藏变量或属性&#xff1a;当你在脚本中使用[HideInInspector]修饰符时&…...

Soanrquber集成Gitlab 之 导入Gitlab项目

集成Gitlab 之 导入Gitlab项目 说明&#xff1a; Sonarquber里面的项目&#xff0c;顺便设置&#xff0c;只要在集成CI的时候&#xff0c;使用这个项目的项目标识即可。 当然项目名称一一对应是最好的了&#xff0c;所以这里讲导入Gitlab的项目&#xff0c;项目名称一一对应&…...

HFSS仿真结果怎么看?一文读懂S参数与电场图,让你的T型波导分析不再迷茫

HFSS仿真结果深度解析&#xff1a;从S参数到电场图的工程实践指南面对HFSS仿真生成的复杂数据图表&#xff0c;许多工程师常陷入"看得见数据却读不懂含义"的困境。本文将带您穿透数据表象&#xff0c;掌握T型波导性能分析的核心方法论。1. S参数&#xff1a;波导性能…...

户外实用|艾迪欧 R6000 测评 —— 户外 / 自驾 / 露营的通讯好搭档

户外出行&#xff0c;通讯工具的核心是稳定、清晰、耐用、续航久、功能全。艾迪欧 R6000 作为一款兼顾专业与户外的 DMR 对讲机&#xff0c;全频段覆盖、双模通讯、自定义功能、长续航&#xff0c;完美适配自驾、露营、登山、越野等户外场景&#xff0c;是户外爱好者的靠谱通讯…...

为什么软件开发偏爱 Linux?深度剖析 Linux 相较于 Windows 的核心优势

引言 在软件开发的世界里&#xff0c;一个有趣的现象是&#xff1a;无论是大型互联网公司的服务器集群&#xff0c;还是资深程序员的个人开发机&#xff0c;Linux 操作系统的身影无处不在。与之形成鲜明对比的是&#xff0c;尽管 Windows 在个人消费市场占据绝对主导地位&…...

XML 服务器

XML 服务器 引言 XML(可扩展标记语言)服务器在现代互联网技术中扮演着至关重要的角色。它为数据的传输和处理提供了灵活且高效的方式。本文将深入探讨XML服务器的概念、工作原理、应用场景及其在软件开发中的重要性。 什么是XML服务器? XML服务器是一种用于存储、处理和…...

AI IDE 革命:程序员正在被重新定义

很多开发者第一次使用 Cursor 的 CtrlK 或 Composer&#xff08;高级多文件编辑模式&#xff09;时&#xff0c;都会有一种强烈的、甚至让人有些脊背发凉的冲击感。 因为&#xff1a; 它已经不再是那个我们熟悉的、只能在原地等待光标落下的&#xff1a; “代码自动补全插件&am…...

Frida无Root Hook PC微信小程序源码(Electron+Chromium)

1. 这不是“破解”&#xff0c;而是一次对微信小程序运行机制的逆向观察 你有没有试过&#xff0c;在PC版微信里点开一个小程序&#xff0c;想看看它背后是怎么写的&#xff1f;比如某个电商小程序的优惠券逻辑、某个工具类小程序的数据渲染方式&#xff0c;甚至只是单纯好奇—…...

人工智能的伦理与安全:这3个问题,软件测试从业者必须重视

随着大语言模型、生成式AI的爆发式落地&#xff0c;人工智能已经从实验室走向千行百业的生产场景&#xff0c;深刻改变着软件开发与交付的逻辑。对于直接把控产品质量关口的软件测试从业者来说&#xff0c;我们的职责早已不再是单纯验证功能可用性、排查性能bug那么简单——AI系…...

内存申请和使用的场景分析(以AP->kernal->ISP为例)

在 ISP&#xff08;Image Signal Processor&#xff09;系统中&#xff0c;AP 与 ISP 之间的内存交互本质上是一个**“AP 申请可 DMA 访问的共享内存 → 内核建立映射 → 硬件寻址读写 → 同步与回收”**的过程。下面按数据流分层详细拆解。一、ISP 内存需求的特殊性 与普通应用…...

SHAP原理与特征贡献解析

SHAP&#xff08;SHapley Additive exPlanations&#xff09;是一种基于博弈论中Shapley值的模型解释方法&#xff0c;它为机器学习模型的预测提供了一种统一、理论完备的特征归因框架。其核心思想是将模型的预测值视为所有特征协同合作的“总收益”&#xff0c;然后公平地分配…...

监控摄像头小众场景爆发,融合类产品成新蓝海

随着户外运动热潮的持续和物联网技术的全面落地&#xff0c;打猎相机市场在2025年迎来了真正的爆发期&#xff0c;并在2026年继续向智能化、网联化深度演进。根据最新的行业监测数据&#xff0c;2025年全球消费类IPC&#xff08;网络摄像机&#xff09;出货量突破1.92亿台&…...