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

news2024/11/6 0:01:37

了解

  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);    
            //绘制Header
            arrayList.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;
        else
            return 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);
            //绘制Header
            arrayList.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();
    }
}

参考

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LBPH算法实现人脸匹配

在当今数字化时代&#xff0c;人脸检测技术在众多领域都发挥着至关重要的作用&#xff0c;从安防监控到智能手机的解锁功能等。今天&#xff0c;就让我们深入了解一下其中一种常用的人脸检测方法 ——LBPH&#xff08;Local Binary Patterns Histograms&#xff09;&#xff0c…

遥感图像Trento原始数据集下载

遥感图像Trento原始数据集下载 偶然间在某个项目里发现了Trento的完整数据集&#xff0c;不过那个数据集有些奇怪的小改动 虽然我已经不做遥感方向了&#xff0c;不过当初我找这个数据集也是花了很长时间 于是重新整理了一下&#xff0c;就当是方便后来的研究者使用吧 githu…

洛雪音乐 1.6.1| 全网音乐免费听,附加音源

洛雪音乐汇集了多个平台的音乐资源&#xff0c;让你可以免费播放各种热门音乐。有经典怀旧的老歌&#xff0c;有最近火爆网络的热曲&#xff0c;还有很多原创音乐人发布的最新作品。因触动资本利益&#xff0c;现已转为空壳软件&#xff0c;需要导入音源来使用。功能特点包括&a…

Flutter学习笔记(二)------ 第一个flutter项目

一、Dart语法 dart语法较为简单&#xff0c;学过python和c后发现大同小异。不过多介绍 1.函数可变参数 可以类比*args, **kwargs&#xff0c;与之不同的是dart中&#xff0c;*args **kwargs不能同时存在 void a(int a, [float x, double b0.0]) {//do something... }a(10, …

【项目小技巧】【C++】 Debug 日志输出 调用者的函数名,所在文件名和行号

文章目录 一、先编写好输出日志的函数二、使用宏定义新的函数三、效果展示 一、先编写好输出日志的函数 /*** 输出 Debug 信息* param [message] [debug 信息]* param [fileName] [调用该函数的文件名字]* param [line] [在文件的第几行]**/ void DebugLog(std::string messag…

行业应用 | 克劳斯玛菲磁力换模项目案例分享

包装行业的发展趋势表明&#xff0c;绿色包装和技术创新是未来的重要方向。双色注塑机的应用正好符合这一趋势&#xff0c;因为它能够减少材料使用&#xff0c;提高生产效率&#xff0c;同时生产出更具吸引力和功能性的包装产品。随着技术的进步和市场需求的增长&#xff0c;双…

音视频入门基础:FLV专题(22)——FFmpeg源码中,获取FLV文件音频信息的实现(中)

本文接着《音视频入门基础&#xff1a;FLV专题&#xff08;21&#xff09;——FFmpeg源码中&#xff0c;获取FLV文件音频信息的实现&#xff08;上&#xff09;》&#xff0c;继续讲解FFmpeg获取FLV文件的音频信息到底是从哪个地方获取的。本文的一级标题从“四”开始。 四、音…

Hudi Upsert原理

1. 前言 如果要深入了解Apache Hudi技术的应用或是性能调优&#xff0c;那么明白源码中的原理对我们会有很大的帮助。Upsert是Apache Hudi的核心功能之一&#xff0c;主要完成增量数据在HDFS/对象存储上的修改&#xff0c;并可以支持事务。而在Hive中修改数据需要重新分区或重…

Proteus中单片机IO口外接LED输出低电平时,引脚却一直保持高电平的问题(已解决)

文章目录 前言解决方法后记 前言 一个排阻接八个 LED&#xff0c;方便又省事&#xff0c;但出现了P1端口输出低电平后&#xff0c;仿真引脚却一直显示红色保持高电平不变&#xff0c;用电压表测量显示 2V 左右。 这是仿真的问题&#xff0c;在用开发板时是不会遇到的&#xff…

医院信息化与智能化系统(15)

医院信息化与智能化系统(15) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应…

系统集成项目管理工程师考试时间

系统集成项目管理基础知识考试信息 题量&#xff1a;共 75 道题。考试时间&#xff1a;该科目考试时间为上午 8&#xff1a;30 - 12&#xff1a;30&#xff08;或下午 14&#xff1a;30 - 18&#xff1a;30&#xff0c;但通常为上午&#xff09;。基础知识科目最短作答时长 90…

数据结构 ——— 向上调整建堆和向下调整建堆的区别

目录 前言 向下调整算法&#xff08;默认小堆&#xff09; 利用向下调整算法对数组建堆 向上调整建堆和向下调整建堆的区别​编辑 向下调整建堆的时间复杂度&#xff1a; 向上调整建堆的时间复杂度&#xff1a; 结论 前言 在上一章讲解到了利用向上调整算法对数组进行…

Handler、Looper、message进阶知识

Android Handler、Looper、Message的进阶知识 在Android开发中&#xff0c;Handler、Looper和Message机制是多线程通信的核心。为了深入理解并优化它们的使用&#xff0c;尤其是在高并发和UI性能优化中&#xff0c;可以利用一些高级特性。 1. Handler的高阶知识 Handler在基本…

【设计模式系列】迭代器模式(七)

一、什么是迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供一种方法来顺序访问一个聚合对象中的各个元素&#xff0c;而不暴露其内部的表示。迭代器模式将集合的遍历过程封装在一个独立的迭代器对象中&#xff0c;这样…

C++基础三(构造函数,形参默认值,函数重载,单例模式,析构函数,内联函数,拷贝构造函数)

C有六个默认函数&#xff0c;分别是&#xff1a; 1、默认构造函数; 2、默认拷贝构造函数; 3、默认析构函数; 4、赋值运算符; 5、取址运算符; 6、取址运算符const; 构造函数 构造函数(初始化类成员变量)&#xff1a; 1、属于类的成员函数之一 …

【C语言学习笔记】

C语言发展史&#xff1a; 1960 原型A语言->ALGOL语言 1963 CPL语言1967 BCPL1970 B语言1973 C语言 C语言特点&#xff1a; 基础性语言语法简洁 紧凑 方便 灵活(得益于指针)运算符 数据结构丰富结构化 模块化编程移植性好 执行效率…

智慧城市的守护者——智能井盖监测终端

城市化进程的加速推进使得基础设施建设成为提升城市品质的关键环节。然而&#xff0c;在这一进程中&#xff0c;市政公用设施中的井盖与地下线缆的安全问题却日益凸显。由于缺乏有效的实时监控与管理体系&#xff0c;给犯罪分子留下了可趁之机&#xff0c;频繁发生的井盖被盗及…

C语言 | Leetcode C语言题解之第513题找树左下角的值

题目&#xff1a; 题解&#xff1a; #define MAX_NODE_SIZE 10000int findBottomLeftValue(struct TreeNode* root){int ret;struct TreeNode** queue (struct TreeNode **)malloc(sizeof(struct TreeNode) * MAX_NODE_SIZE);int head 0;int tail 0;queue[tail] root;whil…

HarmonyOS应用开发者基础认证——初级闯关习题参考答案大全

相关文章 HarmonyOS应用开发者中级认证——中级闯关习题参考答案大全 HarmonyOS应用开发者高级认证——高级闯关习题参考答案大全 文章目录 HarmonyOS第一课 HarmonyOS介绍判断题单选题多选题 HarmonyOS第一课 DevEco Studio的使用判断题单选题多选题 HarmonyOS第一课 ArkTS语法…

SpringBoot 集成 Mybatis-Plus,LambdaQueryWrapper 使用方法

&#x1f3dd;️ 博主介绍 大家好&#xff0c;我是 一个搬砖的农民工&#xff0c;很高兴认识大家 &#x1f60a; ~ &#x1f468;‍&#x1f393; 个人介绍&#xff1a;本人是一名后端Java开发工程师&#xff0c;坐标北京 ~ &#x1f389; 感谢关注 &#x1f4d6; 一起学习 &am…