• Unity ScriptableObject自定义属性显示


    1. 继承Editor,重写OnInspectorGUI方法

    Editor官方文档

    需求

    将TestClass中intData属性和stringData按指定格式显示。

    实现

    定义一个测试类TestClass,一个可序列化类DataClass

    [CreateAssetMenu]
    public class TestClass : ScriptableObject
    {
        [Range(0, 10)]
        public int intData;
        public string stringData;
        public List<DataClass> dataList;
    }
    [System.Serializable]
    public class DataClass
    {
        [Range(0, 100)]
        public int id;
        public Vector3 position;
        public List<int> 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嵌套

    通过Edtiro.CreateEditor可实现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的默认UI
    10         base.OnInspectorGUI();
    11         GUILayout.Space(20);
    12         var data = ( (TestClass2)target ).data;
    13         if(data != null)
    14         {
    15             //创建TestClass的Editor
    16             if (cacheEditor == null)
    17                 cacheEditor = Editor.CreateEditor(data);
    18             GUILayout.Label("this is TestClass2");
    19             cacheEditor.OnInspectorGUI();
    20         }
    21     }
    22 }

    这样就可以直接在TestClass2的面板中直接查看和编辑TestClass的属性。

    2. 使用PropertyDrawer

    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按钮。

    注意事项

    1. PropertyDrawer只对可序列化的类有效,非可序列化的类没法在Inspector面板中显示。
    2. OnGUI方法里只能使用GUI相关方法,不能使用Layout相关方法。
    3. PropertyDrawer对应类型的所有属性的显示方式都会修改,例如创建一个带string属性的MonoBehaviour:

    3. 使用PropertyAttribute

    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 : PropertyDrawer
    13 {
    14     // Draw the property inside the given rect
    15     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    16     {
    17         // First get the attribute since it contains the range for the slider
    18         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         else
    25             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 List<DataClass> dataList;
     8 }
     9 [System.Serializable]
    10 public class DataClass
    11 {
    12     [Range(0, 100)]
    13     public int id;
    14     public Vector3 position;
    15     public List<int> list;
    16 }

    其他

    • 需要修改显示的类都需要满足Unity的序列化规则
    • 这几种显示方式对Serializable Class都可以使用,并不需要一定是ScriptableObject。只是在编辑器下,ScriptableObject来保存临时数据比较常用,所以使用ScriptableObject来做例子。

    转载请注明出处:http://www.cnblogs.com/chiguozi/p/6873050.html 

  • 相关阅读:
    BZOJ.2916.[POI1997]Monochromatic Triangles(三元环)
    Codeforces.724G.Xor-matic Number of the Graph(线性基)
    BZOJ.3498.[PA2009]Cakes(三元环 枚举)
    BZOJ.3545.[ONTAK2010]Peaks(线段树合并)
    BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
    BZOJ.2212.[POI2011]Tree Rotations(线段树合并)
    BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)
    Codeforces.547C.Mike and Foam(容斥/莫比乌斯反演)
    BZOJ.4516.[SCOI2016]幸运数字(线性基 点分治)
    页面置换算法
  • 原文地址:https://www.cnblogs.com/chiguozi/p/6873050.html
Copyright © 2020-2023  润新知