Unity中如何删除自定义数组元素?自定义Inspector删除功能问题
解决自定义数组Inspector的元素选中与删除问题
针对你用PropertyDrawer实现自定义Package数组Inspector时遇到的选中元素并删除的问题,这里提供直接可落地的实现方案:
核心思路
- 在自定义数组的
PropertyDrawer中维护一个选中索引变量,记录用户点击的元素位置 - 给每个数组元素的绘制区域添加点击检测,点击时更新选中索引并高亮元素
- 基于选中索引实现删除逻辑,同时处理编辑器的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
相关产品推荐
相关产品推荐

