Unity CustomPropertyDrawer异常:数组元素修改错位问题
Unity自定义LabeledArrayAttribute数组元素修改偏移问题修复
我实现了一个LabeledArrayAttribute,用来替换Unity Inspector中数组默认的“Element 0”“Element 1”这类标签,支持直接传入字符串数组或枚举类型生成自定义元素名称。但使用时发现异常:
- 当数组元素数量对应枚举长度(20个)时,修改第一个元素,变更会显示在第二个元素上,以此类推
- 仅1个元素时,修改操作无可见效果
- 第21个及以后的元素功能正常
原实现代码
属性定义与测试类
public class LabeledArrayAttribute : PropertyAttribute { public readonly string[] names; public LabeledArrayAttribute(string[] names) { this.names = names; } public LabeledArrayAttribute(Type enumType) { names = Enum.GetNames(enumType); } } public class ColorManager : MonoBehaviour { public enum FollowColor { Accent, Background, Border, Button, Disabled, Error, Foreground, Header, Highlight, Hover, Info, Link, Primary, Secondary, Selected, Success, Tab, Tetriary, Text, Warning } [LabeledArray(typeof(FollowColor))] public Color[] Colors = new Color[20]; }
自定义PropertyDrawer
[CustomPropertyDrawer(typeof(LabeledArrayAttribute))] public class LabeledArrayDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUI.GetPropertyHeight(property, label, true); } public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) { try { EditorGUI.BeginProperty(rect, label, property); var path = property.propertyPath; int pos = int.Parse(path.Split('[').LastOrDefault().TrimEnd(']')); EditorGUI.PropertyField(rect, property, new GUIContent(((LabeledArrayAttribute) attribute).names[pos]), true); EditorGUI.EndProperty(); } catch { EditorGUI.PropertyField(rect, property, label, true); } } }
问题原因
通过字符串分割propertyPath获取数组元素索引的方式不可靠,Unity内部序列化路径的格式可能存在变化,导致解析出的索引与实际元素索引偏移,进而出现修改操作错位的情况。
修复方案
使用Unity官方提供的SerializedProperty.GetArrayElementIndex()方法直接获取元素在数组中的索引,该方法能准确返回当前元素的数组索引,避免字符串解析的误差。同时增加索引范围判断,避免数组越界异常。
修改后的PropertyDrawer代码
[CustomPropertyDrawer(typeof(LabeledArrayAttribute))] public class LabeledArrayDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUI.GetPropertyHeight(property, label, true); } public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label) { try { EditorGUI.BeginProperty(rect, label, property); // 使用官方方法获取数组元素索引,替代字符串分割 int pos = property.GetArrayElementIndex(); var labeledAttribute = (LabeledArrayAttribute)attribute; // 确保索引在有效范围内,避免越界 if (pos >= 0 && pos < labeledAttribute.names.Length) { EditorGUI.PropertyField(rect, property, new GUIContent(labeledAttribute.names[pos]), true); } else { // 超出自定义名称范围时,使用默认标签 EditorGUI.PropertyField(rect, property, label, true); } EditorGUI.EndProperty(); } catch { EditorGUI.PropertyField(rect, property, label, true); } } }
内容的提问来源于stack exchange,提问作者Jaimin Vashi
相关产品推荐
相关产品推荐

