如何在Unity自定义检视器中移除数组加减按钮并锁定数组大小?
自定义EnumNamedArray属性检视器的扩展方案
我用Unity论坛里bonzairob分享的EnumNamedArrayAttribute PropertyDrawer,改了点细节后使用效果不错,但数组长度变化时存在小问题。现在想扩展两个功能:
- 移除数组底部的加减按钮
- 让Array Size字段不可编辑
刚接触自定义检视器,搜不到合适的解决方案,附上当前代码:
using UnityEngine; using UnityEditor; [CustomPropertyDrawer(typeof(EnumNamedArrayAttribute))] public class DrawerEnumNamedArray : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EnumNamedArrayAttribute enumNames = attribute as EnumNamedArrayAttribute; string[] variableName = property.propertyPath.Split('.'); SerializedProperty p = property.serializedObject.FindProperty(variableName[0]); if(p.arraySize != enumNames.names.Length) { p.arraySize = enumNames.names.Length; } int index = System.Convert.ToInt32(property.propertyPath.Substring(property.propertyPath.IndexOf("[")).Replace("[", "").Replace("]", "")); if (index < enumNames.names.Length) { label.text = enumNames.names[index]; } EditorGUI.PropertyField( position, property, label, true ); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUI.GetPropertyHeight(property, label, true); } }
修改后的完整代码
要实现需求,需要跳过Unity默认的数组绘制逻辑(包含Size字段和加减按钮),手动绘制数组的折叠面板和每个元素:
using UnityEngine; using UnityEditor; [CustomPropertyDrawer(typeof(EnumNamedArrayAttribute))] public class DrawerEnumNamedArray : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EnumNamedArrayAttribute enumNames = attribute as EnumNamedArrayAttribute; // 处理数组本身,隐藏默认的Size字段与加减按钮 if (property.isArray) { // 强制数组长度与枚举名称数组一致,禁止手动修改 if (property.arraySize != enumNames.names.Length) { property.arraySize = enumNames.names.Length; } // 绘制数组折叠标签 property.isExpanded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), property.isExpanded, label); if (property.isExpanded) { EditorGUI.indentLevel++; float yOffset = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; // 遍历绘制每个数组元素 for (int i = 0; i < property.arraySize; i++) { SerializedProperty element = property.GetArrayElementAtIndex(i); float elementHeight = EditorGUI.GetPropertyHeight(element, GUIContent.none, true); Rect elementRect = new Rect(position.x, position.y + yOffset, position.width, elementHeight); // 设置元素显示名称为枚举对应文本 GUIContent elementLabel = new GUIContent(enumNames.names[i]); EditorGUI.PropertyField(elementRect, element, elementLabel, true); yOffset += elementHeight + EditorGUIUtility.standardVerticalSpacing; } EditorGUI.indentLevel--; } } // 处理单个数组元素的绘制逻辑(兼容特殊场景) else { int index = int.Parse(property.propertyPath.Substring(property.propertyPath.IndexOf('[')).Replace("[", "").Replace("]", "")); if (index < enumNames.names.Length) { label.text = enumNames.names[index]; } EditorGUI.PropertyField(position, property, label, true); } } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { EnumNamedArrayAttribute enumNames = attribute as EnumNamedArrayAttribute; if (property.isArray) { float height = EditorGUIUtility.singleLineHeight; // 展开状态下计算所有元素的高度总和 if (property.isExpanded) { height += EditorGUIUtility.standardVerticalSpacing; for (int i = 0; i < property.arraySize; i++) { SerializedProperty element = property.GetArrayElementAtIndex(i); height += EditorGUI.GetPropertyHeight(element, GUIContent.none, true) + EditorGUIUtility.standardVerticalSpacing; } } return height; } else { return EditorGUI.GetPropertyHeight(property, label, true); } } }
关键修改说明
- 跳过默认数组绘制:判断
property.isArray后,手动绘制折叠面板和元素,不再调用Unity默认的数组绘制逻辑,自然隐藏Size字段和加减按钮 - 锁定数组长度:强制数组长度与
enumNames.names一致,确保无法通过任何方式修改数组长度 - 适配高度计算:重写
GetPropertyHeight,根据数组展开/折叠状态计算整体高度,避免UI重叠 - 保留元素命名逻辑:延续原有的枚举名称替换数组元素标签的功能
内容的提问来源于stack exchange,提问作者Questy
相关产品推荐
相关产品推荐

