Unity 编辑器扩展六 PropertyDrawer

2021-12-10  本文已影响0人  合肥黑

参考
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

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

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

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

注意这个:

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

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

上一篇 下一篇

猜你喜欢

热点阅读