了解
- 单行高度:EditorGUIUtility.singleLineHeight
- 获取 PropertyField 控件所需的高度:EditorGUI.GetPropertyHeight
- 属性是否在Inspector窗口展开:SerializedProperty.isExpanded
- 可重新排序列表类:ReorderableList
- 绘制纯色矩形:EditorGUI.DrawRect
示例
使用版本:2021.3.6f1c1
此版本的Unity已经实现数组元素添加,移除,移动功能。
自定义类
[System.Serializable]
public class Test
{
public string name;
public int age;
}
数据类
定义一个数组,数组元素为自定义类
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu]
public class TestSO : ScriptableObject
{
public List<Test> testList;
}
数据类文件默认显示如下
修改数据类显示
数据元素内容显示为一行
注意:不能使用自动布局api
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(Test))]
public class TestDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var spName = property.FindPropertyRelative("name");
var spAge = property.FindPropertyRelative("age");
var rect1 = position;
var rect2 = position;
var indentlevel = EditorGUI.indentLevel;
var lableWidth = EditorGUIUtility.labelWidth;
EditorGUI.indentLevel = 2;
EditorGUIUtility.labelWidth = 60;
rect1.width = position.width / 2;
rect1.height = EditorGUIUtility.singleLineHeight;
rect2.width = position.width / 2;
rect2.height = EditorGUIUtility.singleLineHeight;
rect2.x = position.width / 2+40;
rect2.y = rect1.y;
EditorGUI.PropertyField(rect1, spName, new GUIContent("名字"));
EditorGUI.PropertyField(rect2, spAge, new GUIContent("年龄"));
EditorGUI.indentLevel = indentlevel;
EditorGUIUtility.labelWidth = lableWidth;
//EditorGUI.DrawRect(rect1, Color.green);
//EditorGUI.DrawRect(rect2, Color.gray);
}
//获取属性高度
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return base.GetPropertyHeight(property, label);
}
}
修改后显示效果如下图所示
TestList修改为指定名称;Element修改为指定名称
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(TestSO))]
public class TestSOEditor : Editor
{
SerializedProperty sPTestList;
ReorderableList arrayList;
private void OnEnable()
{
sPTestList = serializedObject.FindProperty("testList");
if (arrayList == null)
{
arrayList = new ReorderableList(serializedObject, sPTestList, true, true, true, true);
//绘制Header
arrayList.drawHeaderCallback += DrawHeader;
//绘制数组元素
arrayList.drawElementCallback += DrawElement;
//获取数组的高度
arrayList.elementHeightCallback += DrawElementHeight;
}
}
void DrawHeader(Rect rect)
{
EditorGUI.LabelField(rect, "测试列表");
}
void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
var element = sPTestList.GetArrayElementAtIndex(index);
var arrowRect = rect;
int indentLevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 1;
arrowRect.height = EditorGUIUtility.singleLineHeight;
element.isExpanded = EditorGUI.Foldout(arrowRect, element.isExpanded, new GUIContent("元素" + index));
EditorGUI.indentLevel = indentLevel;
//EditorGUI.DrawRect(rect, Color.red);
//EditorGUI.DrawRect(arrowRect, Color.blue);
if (element.isExpanded)
{
rect.y += arrowRect.height;
EditorGUI.PropertyField(rect, element);
}
}
float DrawElementHeight(int index)
{
var element = sPTestList.GetArrayElementAtIndex(index);
var height = EditorGUIUtility.singleLineHeight;//折叠箭头的高度
if (element.isExpanded)//如果元素展开 获取展开内容的高度和箭头的高度之和
height += EditorGUI.GetPropertyHeight(element);
return height;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
arrayList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
}
修改后如下图所示
示例二
高度计算放在PropertyDrawer的OnGUI中
自定义类
显示折叠箭头,数据元素内容显示为一行,Element修改为指定名称
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(Test))]
public class TestDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var spName = property.FindPropertyRelative("name");
var spAge = property.FindPropertyRelative("age");
var rect0 = position;
rect0.height = EditorGUIUtility.singleLineHeight;
var indentlevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 1;
property.isExpanded = EditorGUI.Foldout(rect0, property.isExpanded, label);
EditorGUI.indentLevel = indentlevel;
if (property.isExpanded)
{
var rect1 = position;
var rect2 = position;
indentlevel = EditorGUI.indentLevel;
var lableWidth = EditorGUIUtility.labelWidth;
EditorGUI.indentLevel = 2;
EditorGUIUtility.labelWidth = 60;
rect1.width = position.width / 2;
rect1.height = EditorGUIUtility.singleLineHeight;
rect1.y += EditorGUIUtility.singleLineHeight;
rect2.width = position.width / 2;
rect2.height = EditorGUIUtility.singleLineHeight;
rect2.x = position.width / 2 + 40;
rect2.y = rect1.y;
EditorGUI.PropertyField(rect1, spName, new GUIContent("名字"));
EditorGUI.PropertyField(rect2, spAge, new GUIContent("年龄"));
EditorGUI.indentLevel = indentlevel;
EditorGUIUtility.labelWidth = lableWidth;
//EditorGUI.DrawRect(rect1, Color.green);
//EditorGUI.DrawRect(rect2, Color.gray);
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property.isExpanded)
return EditorGUIUtility.singleLineHeight * 2;
else
return EditorGUIUtility.singleLineHeight;
}
}
数据类
TestList修改为指定名称
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(TestSO))]
public class TestSOEditor : Editor
{
SerializedProperty sPTestList;
ReorderableList arrayList;
private void OnEnable()
{
sPTestList = serializedObject.FindProperty("testList");
if (arrayList == null)
{
arrayList = new ReorderableList(serializedObject, sPTestList, true, true, true, true);
//绘制Header
arrayList.drawHeaderCallback += DrawHeader;
//绘制数组元素
arrayList.drawElementCallback += DrawElement;
//绘制元素高度
arrayList.elementHeightCallback += DrawHeight;
void DrawHeader(Rect rect)
{
EditorGUI.LabelField(rect, "测试列表");
}
void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
//参数会传递给PropertyDrawer的OnGUI
EditorGUI.PropertyField(rect, sPTestList.GetArrayElementAtIndex(index), new GUIContent("元素 " + index));
}
float DrawHeight(int index)
{
return EditorGUI.GetPropertyHeight(sPTestList.GetArrayElementAtIndex(index));
}
}
}
public override void OnInspectorGUI()
{
serializedObject.Update();
arrayList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
}
参考
看完后理解列表的高度如何计算