当前位置: 代码迷 >> 综合 >> Unity Inspector ReorderableList
  详细解决方案

Unity Inspector ReorderableList

热度:70   发布时间:2023-12-22 16:22:24.0

「Unity3D」(10)自定义属性面板Inspector详解

  Unity: make your lists functional with ReorderableList

  Unity ReorderableList 可重新排序的列表框使用

//Test.csusing System;
using UnityEngine;public class Test : MonoBehaviour {[Serializable]public class Item {public string name;public GameObject[] objs;}public Item[] itemList;
}

SerializedObject:表示当前Inspector选中的一个或多个对象的序列化对象,是当前Inspector的可绘制对象。

EditorGUIUtility.standardVerticalSpacing:默认情况下控件之间的垂直间距使用的高度

EditorGUI.GetPropertyHeight:获取PropertyField控件所需的高度

SerializedObject.FindProperty:通过名称查找序列化的属性

SerializedProperty.FindPropertyRelative:在相对于当前属性的相对路径中检索SerializedProperty

SerializedObject.Update:更新序列化对象的表示形式

ReorderableList.DoLayoutList:自动布局绘制列表

SerializedObject.ApplyModifiedProperties:应用属性修改

//TestEditor.csusing 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");    //在相对于当前属性的相对路径中检索SerializedPropertyEditorGUI.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

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.csusing 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");    //在相对于当前属性的相对路径中检索SerializedPropertyEditorGUI.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的nametypeElement.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);    //如折叠,则不需要加上amountHeightreturn height + space;}public override void OnInspectorGUI() {serializedObject.Update();    //更新序列化对象的表示形式reorderableOneList.DoLayoutList();    //自动布局绘制列表reorderableTwoList.DoLayoutList();serializedObject.ApplyModifiedProperties();    //应用属性修改}
}

  相关解决方案