1. 继承Editor,重写OnInspectorGUI方法
需求
将TestClass中intData属性和stringData按指定格式显示。
实现
定义一个测试类TestClass,一个可序列化类DataClass
[CreateAssetMenu]public class TestClass : ScriptableObject{ [Range(0, 10)] public int intData; public string stringData; public ListdataList;}[System.Serializable]public class DataClass{ [Range(0, 100)] public int id; public Vector3 position; public List list;}
//指定类型[CustomEditor(typeof(TestClass))]public class TestClassEditor : Editor{ SerializedProperty intField; SerializedProperty stringField; void OnEnable() { intField = serializedObject.FindProperty("intData"); stringField = serializedObject.FindProperty("stringData"); } public override void OnInspectorGUI() { // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. serializedObject.Update(); EditorGUILayout.IntSlider(intField, 0, 100, new GUIContent("initData")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(stringField); if(GUILayout.Button("Select")) { stringField.stringValue = EditorUtility.OpenFilePanel("", Application.dataPath, ""); } EditorGUILayout.EndHorizontal(); // Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI. //需要在OnInspectorGUI之前修改属性,否则无法修改值 serializedObject.ApplyModifiedProperties(); base.OnInspectorGUI(); }}
Editor嵌套
通过可实现Editor的嵌套。
创建一个类TestClass2,它包含一个TestClass的属性。
[CreateAssetMenu]public class TestClass2 : ScriptableObject{ public TestClass data;}
创建一个Test2Class的asset。它的Inspector面板的默认显示:
它并没有把TestClass的属性显示出来,如果要查看TestClass的属性,必须双击,跳到相应界面,但这样有看不到TestClass2的属性。
如果想在Test2Class的Inspector面板中直接看到并且可以修改TestClass的属性,可以重写TestClass2的Editor,并在其中嵌套TestClass的Editor。
1 [CustomEditor(typeof(TestClass2))] 2 public class TestClass2Editor : Editor 3 { 4 Editor cacheEditor; 5 public override void OnInspectorGUI() 6 { 7 // Update the serializedProperty - always do this in the beginning of OnInspectorGUI. 8 serializedObject.Update(); 9 //显示TestClass2的默认UI10 base.OnInspectorGUI();11 GUILayout.Space(20);12 var data = ( (TestClass2)target ).data;13 if(data != null)14 {15 //创建TestClass的Editor16 if (cacheEditor == null)17 cacheEditor = Editor.CreateEditor(data);18 GUILayout.Label("this is TestClass2");19 cacheEditor.OnInspectorGUI();20 }21 }22 }
这样就可以直接在TestClass2的面板中直接查看和编辑TestClass的属性。
2. 使用PropertyDrawer
如果想修改某种特定类型的显示,使用继承Editor的方式就会变得很麻烦,因为所有使用特定类型的asset都需要去实现一个自定义的Editor,效率非常低。这种情况就可以通过继承PropertyDrawer的方式,对指定类型的属性,进行统一显示。
需求
为Inspector面板中的所有string属性添加一个选择文件按钮,选中文件的路径直接赋值给该变量。
实现
1 [CustomPropertyDrawer(typeof(string))] 2 public class StringPropertyDrawer : PropertyDrawer 3 { 4 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 5 { 6 Rect btnRect = new Rect(position); 7 position.width -= 60; 8 btnRect.x += btnRect.width - 60; 9 btnRect.width = 60;10 EditorGUI.BeginProperty(position, label, property);11 EditorGUI.PropertyField(position, property, true);12 if (GUI.Button(btnRect, "select"))13 {14 string path = property.stringValue;15 string selectStr = EditorUtility.OpenFilePanel("选择文件", path, "");16 if (!string.IsNullOrEmpty(selectStr))17 {18 property.stringValue = selectStr;19 }20 }21 EditorGUI.EndProperty();22 }23 }
加了一个PropertyDrawer之后,Inspector面板中的所有string变量都会额外添加一个Select按钮。
注意事项
- PropertyDrawer只对可序列化的类有效,非可序列化的类没法在Inspector面板中显示。
- OnGUI方法里只能使用GUI相关方法,不能使用Layout相关方法。
- PropertyDrawer对应类型的所有属性的显示方式都会修改,例如创建一个带string属性的MonoBehaviour:
3. 使用PropertyAttribute
如果想要修改部分类的指定类型的属性的显示,直接使用PropertyDrawer就无法满足条件,这时可以结合PropertyAttribute和PropertyAttribute来实现需求。
需求
为部分指定类的int或float属性的显示添加滑动条,滑动条的上下限可根据类和属性自行设置。
实现
1 public class RangeAttribute : PropertyAttribute 2 { 3 public float min; 4 public float max; 5 public RangeAttribute(float min, float max) 6 { 7 this.min = min; 8 this.max = max; 9 }10 }11 [CustomPropertyDrawer(typeof(RangeAttribute))]12 public class RangeDrawer : PropertyDrawer13 {14 // Draw the property inside the given rect15 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)16 {17 // First get the attribute since it contains the range for the slider18 RangeAttribute range = attribute as RangeAttribute;19 // Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.20 if (property.propertyType == SerializedPropertyType.Float)21 EditorGUI.Slider(position, property, range.min, range.max, label);22 else if (property.propertyType == SerializedPropertyType.Integer)23 EditorGUI.IntSlider(position, property, (int)range.min, (int)range.max, label);24 else25 EditorGUI.LabelField(position, label.text, "Use Range with float or int.");26 }27 }
修改TestClass和DataClass
1 [CreateAssetMenu] 2 public class TestClass : ScriptableObject 3 { 4 [Range(0, 10)] 5 public int intData; 6 public string stringData; 7 public ListdataList; 8 } 9 [System.Serializable]10 public class DataClass11 {12 [Range(0, 100)]13 public int id;14 public Vector3 position;15 public List list;16 }
其他
- 需要修改显示的类都需要满足
- 这几种显示方式对Serializable Class都可以使用,并不需要一定是ScriptableObject。只是在编辑器下,ScriptableObject来保存临时数据比较常用,所以使用ScriptableObject来做例子。
转载请注明出处: