Unity提供PropertyDrawer使我们可以编写指定类型数据的Inspector,比如我们重写Vector3属性的Inspector面板,那么任何使用Vector3的类,其中Vector3类型的序列化数据在Inspector都会变成我们重写的样式,下面是官方使用PropertyDrawer重写属性的示例代码
// The property drawer class should be placed in an editor script, inside a folder called Editor.
// Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute.
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(RangeAttribute))]
public class RangeDrawer : PropertyDrawer
{
// Draw the property inside the given rect
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// First get the attribute since it contains the range for the slider
RangeAttribute range = attribute as RangeAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label);
else
EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
}
}
// This is not an editor script. The property attribute class should be placed in a regular script file.
using UnityEngine;
public class RangeAttribute : PropertyAttribute
{
public float min;
public float max;
public RangeAttribute(float min, float max)
{
this.min = min;
this.max = max;
}
}
写一个测试代码
public class JCTest
{
public int a;
public RangeAttribute r;
}
通过上面的代码可以看出,如果要使用PropertyDrawer必须使用EditorGUI里的函数,那么如果我们把EditorGUI换成EditorGUILayout,那么我们会得到一个错误
在OnGUI函数中,添加以下两行代码
var evt = UnityEngine.Event.current; Debug.Log(evt.type);
也就是说OnGUI函数会被调用两次,第一次是Layout,第二次是repaint,在Layout中,Unity会为我们自动计算各组件的坐标位置,然后会在repaint时将组件画出来,这也是为什么所有的EditorGUILayout函数不需要我们手动传入Rect的原因,而上面的示例出错也很好理解,原因是PropertyDrawer的属性只是它的数据(JCTest)的Inspector的一部分,所以在显示PropertyDrawer的属性时由于不知道其他组件的位置,所以也无法计算出在OnGUI函数中使用EditorGUILayout创建的组件位置
解决方法:为JCTest添加Editor代码
[CustomEditor(typeof(JCTest))]
public class TBCAssetInspector : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
serializedObject.Update();
SerializedProperty property = serializedObject.GetIterator();
bool expanded = true;
while (property.NextVisible(expanded))
{
expanded = false;
if (SkipField(property.propertyPath))
continue;
EditorGUILayout.PropertyField(property, true);
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
}
static bool SkipField(string fieldName)
{
return fieldName == "m_Script";
}
}
此方法虽然解决了EditorGUILayout编辑PropertyDrawer报错的问题,但也使PropertyDrawer失去了意义,所以建议还是使用EditorGUI行进编辑


文章评论