You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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);
        }
    }
}

关键修改说明

  1. 跳过默认数组绘制:判断property.isArray后,手动绘制折叠面板和元素,不再调用Unity默认的数组绘制逻辑,自然隐藏Size字段和加减按钮
  2. 锁定数组长度:强制数组长度与enumNames.names一致,确保无法通过任何方式修改数组长度
  3. 适配高度计算:重写GetPropertyHeight,根据数组展开/折叠状态计算整体高度,避免UI重叠
  4. 保留元素命名逻辑:延续原有的枚举名称替换数组元素标签的功能

内容的提问来源于stack exchange,提问作者Questy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:05:26