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行进编辑
文章评论