Unity Inspector ReorderableList

简单的ReorderableList

Test.cs

1
2
3
4
5
6
7
8
9
10
11
12
using System;
using UnityEngine;

public class Test : MonoBehaviour {
[Serializable]
public class Item {
public string name;
public GameObject[] objs;
}

public Item[] itemList;
}

TestEditor.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using UnityEditor;
using UnityEditorInternal; //ReorderableList所在命名空间
using UnityEngine;

[CustomEditor(typeof(Test))]
public class TestEditor : Editor {
SerializedProperty itemList;
ReorderableList reorderableList;

//EditorGUIUtility.standardVerticalSpacing 默认情况下控件之间的垂直间距使用的高度
readonly float space = EditorGUIUtility.standardVerticalSpacing;

void OnEnable() {
itemList = serializedObject.FindProperty("itemList"); //通过名称查找序列化的属性
reorderableList = new ReorderableList(serializedObject, itemList, true, true, true, true);
//下列回调皆可写成Lambda表达式
reorderableList.drawHeaderCallback = DrawListHeader;
reorderableList.drawElementCallback = DrawListElement;
reorderableList.elementHeightCallback = ListElementHeight;
}

//绘制表头
void DrawListHeader(Rect rect) {
EditorGUI.LabelField(rect, "itemList");
}

//绘制元素
void DrawListElement(Rect rect, int index, bool selected, bool focused) {
SerializedProperty element = itemList.GetArrayElementAtIndex(index);
rect.y += space;

SerializedProperty name = element.FindPropertyRelative("name"); //在相对于当前属性的相对路径中检索SerializedProperty
EditorGUI.PropertyField(new Rect(rect.x, rect.y, Screen.width * .8f, EditorGUI.GetPropertyHeight(name)), name);

SerializedProperty objs = element.FindPropertyRelative("objs");
EditorGUI.PropertyField(new Rect(rect.x + 12, rect.y + EditorGUI.GetPropertyHeight(name), Screen.width * .8f, EditorGUI.GetPropertyHeight(objs, true)), objs, true);
}

//设置元素高度
float ListElementHeight(int index) {
SerializedProperty element = itemList.GetArrayElementAtIndex(index);
float height = space;

SerializedProperty name = element.FindPropertyRelative("name");
SerializedProperty objs = element.FindPropertyRelative("objs");
height += EditorGUI.GetPropertyHeight(name) + EditorGUI.GetPropertyHeight(objs, true);
return height + space;
}

public override void OnInspectorGUI() {
serializedObject.Update(); //更新序列化对象的表示形式
reorderableList.DoLayoutList(); //自动布局绘制列表
serializedObject.ApplyModifiedProperties(); //应用属性修改
}
}

复杂的ReorderableList

Test.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using UnityEngine;

public class Test : MonoBehaviour {
[Serializable]
public class ItemOne {
public string name;
public GameObject[] objs;
}

[Serializable]
public class ItemTwo {
public BoxCollider trigger;
public string[] types;
public float[] amounts;
public bool fold;
}

public ItemOne[] itemOneList;
public ItemTwo[] itemTwoList;
}

TestEditor.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using UnityEditor;
using UnityEditorInternal; //ReorderableList所在命名空间
using UnityEngine;

[CustomEditor(typeof(Test))]
public class TestEditor : Editor {
SerializedProperty itemOneList;
ReorderableList reorderableOneList;
SerializedProperty itemTwoList;
ReorderableList reorderableTwoList;

//EditorGUIUtility.standardVerticalSpacing 默认情况下控件之间的垂直间距使用的高度
readonly float space = EditorGUIUtility.standardVerticalSpacing;
readonly float foldHeight = 15;
readonly float amountElementHeight = 20;

void OnEnable() {
itemOneList = serializedObject.FindProperty("itemOneList"); //通过名称查找序列化的属性
reorderableOneList = new ReorderableList(serializedObject, itemOneList, true, true, true, true);
//下列回调皆可写成Lambda表达式
reorderableOneList.drawHeaderCallback = DrawOneListHeader;
reorderableOneList.drawElementCallback = DrawOneListElement;
reorderableOneList.elementHeightCallback = OneListElementHeight;

itemTwoList = serializedObject.FindProperty("itemTwoList");
reorderableTwoList = new ReorderableList(serializedObject, itemTwoList, true, true, true, true);
reorderableTwoList.drawHeaderCallback = DrawTwoListHeader;
reorderableTwoList.drawElementCallback = DrawTwoListElement;
reorderableTwoList.elementHeightCallback = TwoListElementHeight;
}

//绘制表头
void DrawOneListHeader(Rect rect) {
EditorGUI.LabelField(rect, "ItemOneList");
}

void DrawTwoListHeader(Rect rect) {
EditorGUI.LabelField(rect, "ItemTwoList");
}

//绘制元素
void DrawOneListElement(Rect rect, int index, bool selected, bool focused) {
SerializedProperty element = itemOneList.GetArrayElementAtIndex(index);
rect.y += space;

SerializedProperty name = element.FindPropertyRelative("name"); //在相对于当前属性的相对路径中检索SerializedProperty
EditorGUI.PropertyField(new Rect(rect.x, rect.y, Screen.width * .8f, EditorGUI.GetPropertyHeight(name)), name);

SerializedProperty objs = element.FindPropertyRelative("objs");
EditorGUI.PropertyField(new Rect(rect.x + 12, rect.y + EditorGUI.GetPropertyHeight(name), Screen.width * .8f, EditorGUI.GetPropertyHeight(objs, true)), objs, true);
}

void DrawTwoListElement(Rect rect, int index, bool selected, bool focused) {
SerializedProperty element = itemTwoList.GetArrayElementAtIndex(index);
rect.y += space;

SerializedProperty trigger = element.FindPropertyRelative("trigger");
float triggerHeight = EditorGUI.GetPropertyHeight(trigger);
EditorGUI.PropertyField(new Rect(rect.x, rect.y, Screen.width * .8f, triggerHeight), trigger);

//折叠
SerializedProperty fold = element.FindPropertyRelative("fold");
fold.boolValue = EditorGUI.Foldout(new Rect(rect.x + 12, rect.y + triggerHeight, Screen.width * .8f, foldHeight), fold.boolValue, "Amounts", true);
if (fold.boolValue) { //如果为true,则应渲染子对象
SerializedProperty types = element.FindPropertyRelative("types");
SerializedProperty amounts = element.FindPropertyRelative("amounts");
types.arraySize = amounts.arraySize = reorderableOneList.count; //设置types数组和amounts数组的容量
for (int i = 0; i < types.arraySize; i++) {
SerializedProperty typeElement = types.GetArrayElementAtIndex(i);
SerializedProperty amountElement = amounts.GetArrayElementAtIndex(i);

SerializedProperty oneListElement = itemOneList.GetArrayElementAtIndex(i);
SerializedProperty name = oneListElement.FindPropertyRelative("name"); //取对应关系的oneListElement的name
typeElement.stringValue = name.stringValue;

EditorGUI.LabelField(new Rect(rect.x + 12, rect.y + triggerHeight + foldHeight + amountElementHeight * i + space * (i + 1), Screen.width * .3f, amountElementHeight), typeElement.stringValue);
amountElement.floatValue = EditorGUI.Slider(new Rect(rect.x + 12 + Screen.width * .3f, rect.y + triggerHeight + foldHeight + amountElementHeight * i + space * (i + 1), Screen.width * .5f, amountElementHeight), amountElement.floatValue, 0, 1);
}
}
}

//设置元素高度
float OneListElementHeight(int index) {
SerializedProperty element = itemOneList.GetArrayElementAtIndex(index);
float height = space;

SerializedProperty name = element.FindPropertyRelative("name");
SerializedProperty objs = element.FindPropertyRelative("objs");
height += EditorGUI.GetPropertyHeight(name) + EditorGUI.GetPropertyHeight(objs, true);
return height + space;
}

float TwoListElementHeight(int index) {
SerializedProperty element = itemTwoList.GetArrayElementAtIndex(index);
float height = space;

SerializedProperty trigger = element.FindPropertyRelative("trigger");
SerializedProperty amounts = element.FindPropertyRelative("amounts");
SerializedProperty fold = element.FindPropertyRelative("fold");
float triggerHeight = EditorGUI.GetPropertyHeight(trigger);
//amount用的是EditorGUI.LabelField和EditorGUI.Slider,不是EditorGUI.PropertyField,所以无法使用EditorGUI.GetPropertyHeight得到高度,需要自己计算
float amountHeight = (amountElementHeight + space) * amounts.arraySize;

height += triggerHeight + foldHeight + (fold.boolValue ? amountHeight : 0f); //如折叠,则不需要加上amountHeight
return height + space;
}

public override void OnInspectorGUI() {
serializedObject.Update(); //更新序列化对象的表示形式
reorderableOneList.DoLayoutList(); //自动布局绘制列表
reorderableTwoList.DoLayoutList();
serializedObject.ApplyModifiedProperties(); //应用属性修改
}
}

相关对象及属性说明

参考

作者

DullSword

发布于

2020-06-24

更新于

2024-07-02

许可协议

评论