Unity 编辑器扩展六 PropertyDrawer

参考
Unity Editor 基础篇(六):Property Drawers
【Unity 编辑器】扩展总结七:数组或list集合的显示方式
Unity自定义ScriptableObject属性显示的三种方式
https://docs.unity.cn/cn/2019.4/Manual/editor-PropertyDrawers.html

如果想修改某种特定类型的显示,使用继承Editor的方式就会变得很麻烦,因为所有使用特定类型的asset都需要去实现一个自定义的Editor,效率非常低。这种情况就可以通过继承PropertyDrawer的方式,对指定类型的属性,进行统一显示。

一、示例
1.Serializable

在Scripts文件夹中创建两个C#脚本,分别命名为:“Person.cs”和“ShowPersonInfo.cs”

public enum Sex
{
    female,
    male
}

public class Person
{
    public string name;
    public Sex sex;
    public int age;
    public string desc;
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShowPersonInfo : MonoBehaviour
{
    public Person persion;
}

要想给一个游戏对象挂上脚本,那么该脚本就必须继承自 MonoBehaviour ,ShowPersonInfo 就是用来做这个的。但是挂上脚本,却发现看不到Person属性。


image.png

要想将一个普通的类里的属性在Inspector面板中显示出来,那么必须将这个普通的类序列化。

public enum Sex
{
    female,
    male
}
[System.Serializable]
public class Person
{
    public string name;
    public Sex sex;
    public int age;
    public string desc;
}
image.png
2.CustomPropertyDrawer

在Editor文件夹中创建一个名为“PersonPropertiesDrawer.cs”的脚本

添加 [CustomPropertyDrawer(typeof(Persion))],指定该类是用于自定义属性的绘制。

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(Person))]
public class PersonPropertiesDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        //base.OnGUI(position, property, label);
        Debug.Log("Label:" + label.text);
        Debug.Log(position);
        while (property.NextVisible(true))
        {
            Debug.Log("OnGUI:" + property.name);
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        while (property.NextVisible(true))
        {
            Debug.Log("GetPropertyHeight:" + property.name);
        }
        return base.GetPropertyHeight(property, label);
    }
}
image.png

从上面的数据可以看出如下几点:

  • OnGUI 和 GetPropertyHeight 里的 property 参数是同一个参数。该参数里存放的是 Persion 里的属性信息。
  • OnGUI 和 GetPropertyHeight 里的 Label 参数也是同一个参数,该参数里存放的是 Persion 类的类名。
  • position参数指的是需要在Inspector面板中绘制的区域信息,可以从下面两张图中简单的了解一下:
image.png

对了还有一个地方克森遗漏掉了,那就是在Inspector面板中的一行高度为 16 。

这里经过我的测试是18,使用如下代码打印一下看看就知道了

Debug.Log("label height:" + base.GetPropertyHeight(property, label));
3.自定义绘制
最终效果
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(Person))]
public class PersonPropertiesDrawer : PropertyDrawer
{
    Rect top, middleRight, middleLeft, bottom;
    SerializedProperty personName, sex, age, desc;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        //顶部区域
        top = new Rect(position.x, position.y, position.width, position.height / 4.0f);
        //中部区域左侧
        middleLeft = new Rect(position.x,
            position.y + (position.height / 4.0f),
            position.width / 2.0f,
            position.height / 4.0f);
        //中部区域右侧
        middleRight = new Rect(position.x + position.width / 2.0f,
            position.y + (position.height / 4.0f),
            position.width / 2.0f,
            position.height / 4.0f);
        //底部区域
        bottom = new Rect(position.x,
            position.y + (position.height / 4.0f) * 2,
            position.width,
            (position.height / 4.0f) * 2);
        //获取对应的序列化属性
        personName = property.FindPropertyRelative("name");
        sex = property.FindPropertyRelative("sex");
        age = property.FindPropertyRelative("age");
        desc = property.FindPropertyRelative("desc");
        //绘制属性
        EditorGUI.PropertyField(top, personName, label);
        EditorGUI.PropertyField(middleLeft, sex);
        EditorGUI.PropertyField(middleRight, age);
        desc.stringValue = EditorGUI.TextArea(bottom, desc.stringValue);
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return base.GetPropertyHeight(property, label) * 4;//4行
    }
}

EditorGUI.PropertyField

  • 第一个参数是该属性绘制在Inspector面板的位置
  • 第二个参数是需要绘制的序列化属性
  • 第三个参数是该属性的标签,默认为null

SerializedProperty.FindPropertyRelative
通过属性的名字获取对应的SerializedProperty

注意这个:

desc.stringValue = EditorGUI.TextArea(bottom, desc.stringValue);

如果删除desc.stringValue =,在面板上输入字符串移开焦点,输入的内容会被清空。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341

推荐阅读更多精彩内容