参考
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属性。
要想将一个普通的类里的属性在Inspector面板中显示出来,那么必须将这个普通的类序列化。
public enum Sex
{
female,
male
}
[System.Serializable]
public class Person
{
public string name;
public Sex sex;
public int age;
public string desc;
}
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);
}
}
从上面的数据可以看出如下几点:
- OnGUI 和 GetPropertyHeight 里的 property 参数是同一个参数。该参数里存放的是 Persion 里的属性信息。
- OnGUI 和 GetPropertyHeight 里的 Label 参数也是同一个参数,该参数里存放的是 Persion 类的类名。
- position参数指的是需要在Inspector面板中绘制的区域信息,可以从下面两张图中简单的了解一下:
对了还有一个地方克森遗漏掉了,那就是在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 =
,在面板上输入字符串移开焦点,输入的内容会被清空。