Unity中自定义Editor对普通Serializable类列表不生效问题求助
问题解决:Serializable类列表中自定义Inspector不生效的问题
我需要存储大量DataFrame类实例,这个类包含众多字段,导致列表显示过长。于是为DataFrame制作了自定义Inspector,希望将其数据压缩为3行显示,但重写OnInspectorGUI后,该类在列表中仍显示默认样式;而将其改为ScriptableObject或MonoBehaviour时,自定义Inspector可正常生效,问题仅出现在列表显示场景中。无[System.Serializable]标签时列表无法显示,相关代码如下:
DataFrame类代码
[System.Serializable] public class DataFrame { public const int LINES_NUMBER = 10; [Header("Units")] public float UnitZombieHealthCoefficient; public int UnitMonsterNumber; [Space(5)] public float UnitEnemyCountCoefficient; [Header("Objects")] public int ObjTrapNumber; public int ObjCoinNumber; [Header("Control point Chance")] public float CpShopCoefficient; public float CpEventCoefficient; public float CpAbibityCoefficient; public float CpCoinsCoefficient; }
原自定义Editor代码
[CustomEditor(typeof(DataFrame))] public class DataStageEditor : Editor { #region SerializedProperties SerializedObject _serializedObject; SerializedProperty _zombieHealthCoefficient; SerializedProperty _monsterNumber; SerializedProperty _enemyCountCoefficient; SerializedProperty _trapNumber; SerializedProperty _coinNumber; SerializedProperty _shopCoefficient; SerializedProperty _eventCoefficient; SerializedProperty _abibityCoefficient; SerializedProperty _coinsCoefficient; #endregion private void OnEnable() { SetProperties(); } private void SetProperties() { _serializedObject = new SerializedObject(target); _zombieHealthCoefficient = _serializedObject.FindProperty(nameof(DataFrame.UnitZombieHealthCoefficient)); _monsterNumber = _serializedObject.FindProperty(nameof(DataFrame.UnitMonsterNumber)); _enemyCountCoefficient = _serializedObject.FindProperty(nameof(DataFrame.UnitEnemyCountCoefficient)); _trapNumber = _serializedObject.FindProperty(nameof(DataFrame.ObjTrapNumber)); _coinNumber = _serializedObject.FindProperty(nameof(DataFrame.ObjCoinNumber)); _shopCoefficient = _serializedObject.FindProperty(nameof(DataFrame.CpShopCoefficient)); _eventCoefficient = _serializedObject.FindProperty(nameof(DataFrame.CpEventCoefficient)); _abibityCoefficient = _serializedObject.FindProperty(nameof(DataFrame.CpAbibityCoefficient)); _coinsCoefficient = _serializedObject.FindProperty(nameof(DataFrame.CpCoinsCoefficient)); } public override void OnInspectorGUI() { EditorGUILayout.LabelField("TEST"); EditorGUILayout.PropertyField(_zombieHealthCoefficient, true); EditorGUILayout.PropertyField(_monsterNumber, true); EditorGUILayout.PropertyField(_enemyCountCoefficient, true); EditorGUILayout.Space(50); EditorGUILayout.PropertyField(_trapNumber, true); EditorGUILayout.PropertyField(_coinNumber, true); EditorGUILayout.PropertyField(_shopCoefficient, true); EditorGUILayout.PropertyField(_eventCoefficient, true); EditorGUILayout.PropertyField(_abibityCoefficient, true); EditorGUILayout.PropertyField(_coinsCoefficient, true); } }
解决方案
问题核心:普通[System.Serializable]标记的类在列表中显示时,Unity不会调用你编写的CustomEditor,CustomEditor仅对继承自UnityEngine.Object的类型(如MonoBehaviour、ScriptableObject)生效。要实现列表中的自定义显示,需要使用PropertyDrawer替代CustomEditor。
实现自定义PropertyDrawer
using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(DataFrame))] public class DataFrameDrawer : PropertyDrawer { // 定义该属性在Inspector中占用的高度(3行+间距) public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUIUtility.singleLineHeight * 3 + EditorGUIUtility.standardVerticalSpacing * 2; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); // 绘制属性前缀标签(保留Unity默认的折叠交互) position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); // 分割出3行的显示区域 var line1Rect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); var line2Rect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); var line3Rect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing)*2, position.width, EditorGUIUtility.singleLineHeight); // 第一行:Units相关字段 var zombieHealthProp = property.FindPropertyRelative(nameof(DataFrame.UnitZombieHealthCoefficient)); var monsterNumProp = property.FindPropertyRelative(nameof(DataFrame.UnitMonsterNumber)); var enemyCountProp = property.FindPropertyRelative(nameof(DataFrame.UnitEnemyCountCoefficient)); EditorGUI.PropertyField(new Rect(line1Rect.x, line1Rect.y, line1Rect.width/3, line1Rect.height), zombieHealthProp, new GUIContent("Zombie HP")); EditorGUI.PropertyField(new Rect(line1Rect.x + line1Rect.width/3, line1Rect.y, line1Rect.width/3, line1Rect.height), monsterNumProp, new GUIContent("Monster Num")); EditorGUI.PropertyField(new Rect(line1Rect.x + line1Rect.width*2/3, line1Rect.y, line1Rect.width/3, line1Rect.height), enemyCountProp, new GUIContent("Enemy Coeff")); // 第二行:Objects相关字段 var trapNumProp = property.FindPropertyRelative(nameof(DataFrame.ObjTrapNumber)); var coinNumProp = property.FindPropertyRelative(nameof(DataFrame.ObjCoinNumber)); EditorGUI.PropertyField(new Rect(line2Rect.x, line2Rect.y, line2Rect.width/2, line2Rect.height), trapNumProp, new GUIContent("Trap Num")); EditorGUI.PropertyField(new Rect(line2Rect.x + line2Rect.width/2, line2Rect.y, line2Rect.width/2, line2Rect.height), coinNumProp, new GUIContent("Coin Num")); // 第三行:Control Point相关字段 var shopProp = property.FindPropertyRelative(nameof(DataFrame.CpShopCoefficient)); var eventProp = property.FindPropertyRelative(nameof(DataFrame.CpEventCoefficient)); var abilityProp = property.FindPropertyRelative(nameof(DataFrame.CpAbibityCoefficient)); var coinsCpProp = property.FindPropertyRelative(nameof(DataFrame.CpCoinsCoefficient)); EditorGUI.PropertyField(new Rect(line3Rect.x, line3Rect.y, line3Rect.width/4, line3Rect.height), shopProp, new GUIContent("Shop")); EditorGUI.PropertyField(new Rect(line3Rect.x + line3Rect.width/4, line3Rect.y, line3Rect.width/4, line3Rect.height), eventProp, new GUIContent("Event")); EditorGUI.PropertyField(new Rect(line3Rect.x + line3Rect.width*2/4, line3Rect.y, line3Rect.width/4, line3Rect.height), abilityProp, new GUIContent("Ability")); EditorGUI.PropertyField(new Rect(line3Rect.x + line3Rect.width*3/4, line3Rect.y, line3Rect.width/4, line3Rect.height), coinsCpProp, new GUIContent("Coins")); EditorGUI.EndProperty(); } }
注意事项
- 原有的
DataStageEditor可以保留,当DataFrame作为独立的ScriptableObject实例被选中时,依然可以用它显示详细信息 PropertyDrawer专门负责处理Serializable类在Inspector(包括列表)中的渲染逻辑,完全适配你的压缩显示需求- 可根据实际需求调整每行的字段布局、标签文字和高度
内容的提问来源于stack exchange,提问作者Aiden VMR
相关产品推荐
相关产品推荐

