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

Unity中如何删除自定义数组元素?自定义Inspector删除功能问题

解决自定义数组Inspector的元素选中与删除问题

针对你用PropertyDrawer实现自定义Package数组Inspector时遇到的选中元素并删除的问题,这里提供直接可落地的实现方案:

核心思路

  1. 在自定义数组的PropertyDrawer中维护一个选中索引变量,记录用户点击的元素位置
  2. 给每个数组元素的绘制区域添加点击检测,点击时更新选中索引并高亮元素
  3. 基于选中索引实现删除逻辑,同时处理编辑器的Undo/Redo保证操作可回退

完整代码示例

假设你的自定义数组类定义如下:

using UnityEngine;
using System.Collections.Generic;

[Serializable]
public class PackageArray
{
    public List<Package> packages = new List<Package>();
}

[Serializable]
public class Package
{
    public string packageName;
    public int version;
    // 你的其他自定义字段
}

对应的数组PropertyDrawer实现:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(PackageArray))]
public class PackageArrayDrawer : PropertyDrawer
{
    private int _selectedIndex = -1;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);
        var packagesProp = property.FindPropertyRelative("packages");

        // 绘制标题和操作按钮
        position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
        using (new EditorGUILayout.HorizontalScope())
        {
            if (GUILayout.Button("添加Package"))
            {
                Undo.RecordObject(property.serializedObject.targetObject, "添加Package");
                packagesProp.arraySize++;
                property.serializedObject.ApplyModifiedProperties();
            }

            using (new EditorGUI.DisabledScope(_selectedIndex == -1))
            {
                if (GUILayout.Button("删除选中Package"))
                {
                    Undo.RecordObject(property.serializedObject.targetObject, "删除Package");
                    packagesProp.DeleteArrayElementAtIndex(_selectedIndex);
                    // 删除后调整选中索引,避免越界
                    _selectedIndex = Mathf.Clamp(_selectedIndex - 1, -1, packagesProp.arraySize - 1);
                    property.serializedObject.ApplyModifiedProperties();
                }
            }
        }

        // 绘制每个Package元素
        for (int i = 0; i < packagesProp.arraySize; i++)
        {
            var elementProp = packagesProp.GetArrayElementAtIndex(i);
            var elementRect = EditorGUILayout.BeginVertical(GUI.skin.box);

            // 检测元素区域点击,更新选中索引
            var currentEvent = Event.current;
            if (currentEvent.type == EventType.MouseDown && elementRect.Contains(currentEvent.mousePosition))
            {
                _selectedIndex = i;
                currentEvent.Use(); // 拦截事件,避免触发其他控件
            }

            // 高亮选中元素
            if (_selectedIndex == i)
            {
                EditorGUI.DrawRect(elementRect, new Color(0.2f, 0.4f, 0.8f, 0.2f));
            }

            // 调用Package的自定义Drawer绘制元素
            EditorGUI.PropertyField(elementRect, elementProp, true);

            EditorGUILayout.EndVertical();
        }

        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        var packagesProp = property.FindPropertyRelative("packages");
        float totalHeight = EditorGUIUtility.singleLineHeight * 2; // 标题和按钮行高度
        for (int i = 0; i < packagesProp.arraySize; i++)
        {
            totalHeight += EditorGUI.GetPropertyHeight(packagesProp.GetArrayElementAtIndex(i), true) + EditorGUIUtility.standardVerticalSpacing;
        }
        return totalHeight;
    }
}

关键细节说明

  • 选中状态管理:用_selectedIndex变量追踪选中元素,点击元素区域时更新该值,并通过绘制半透明背景高亮选中项
  • 事件拦截:调用currentEvent.Use()避免点击事件传递给下层控件,确保选中逻辑唯一触发
  • Undo支持:删除/添加操作前调用Undo.RecordObject,保证编辑器操作可回退,符合Unity编辑器的交互规范
  • 索引越界处理:删除元素后自动调整选中索引,避免后续操作出现数组越界问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:02:39