Unity自定义Enum索引数组PropertyDrawer展开类元素时UI重叠
问题描述
在Unity编辑器中实现了以枚举值作为数组元素索引显示名称的自定义PropertyDrawer,但Inspector面板展开数组时,数组元素属性直接绘制到数组下方的其他UI控件区域,没有为元素完整内容预留显示高度,导致展开的数组UI和下方脚本组件重叠,重叠效果如下:
移除枚举索引自定义绘制逻辑后数组可正常展开。测试验证该自定义绘制逻辑在int、string、float等基础值类型数组上可正常运行,仅在处理包含多个属性的自定义类、结构体数组时触发异常。旧版本Unity中曾遇到嵌套数组同类问题,升级版本即可修复,但当前使用最新正式版Unity,判断问题根源在自定义PropertyDrawer的代码实现中。
复现代码
1. 自定义特性定义
using UnityEngine; public class EnumNamedArrayAttribute : PropertyAttribute { public string[] names; public EnumNamedArrayAttribute(System.Type names_enum_type) { this.names = System.Enum.GetNames(names_enum_type); } }
2. 自定义属性绘制器实现
using UnityEngine; using UnityEditor; using System.Collections; using System.Collections.Generic; [CustomPropertyDrawer(typeof(EnumNamedArrayAttribute))] public class DrawerEnumNamedArray : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EnumNamedArrayAttribute enumNames = attribute as EnumNamedArrayAttribute; //propertyPath返回格式类似component_hp_max.Array.data[4] //从路径中提取索引 int index = System.Convert.ToInt32(property.propertyPath.Substring(property.propertyPath.IndexOf("[")).Replace("[", "").Replace("]", "")); //修改显示标签 label.text = enumNames.names[index]; //绘制属性字段 EditorGUI.PropertyField(position, property, label, true); } }
3. 数组字段声明
[EnumNamedArray(typeof(Spells))] public SpellBlueprint[] spellBlueprints; public enum Spells { fireball,lightningbolt,frostbolt }
4. 数组元素类定义
using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class SpellBlueprint { public float speed = 20f; public float damage = 15f; public bool AOE_enabled = false; public GameObject SpellPrefab; }
补充说明
该枚举命名数组绘制器对int、string、float等基础类型数组完全生效,仅处理包含多个属性的自定义类或结构体时出现布局异常。
问题原因
自定义绘制器没有重写GetPropertyHeight方法,Unity默认只返回单行属性的高度。基础类型数组元素都是单行高度,所以不会出现重叠;自定义类/结构体展开后是多行内容,高度计算错误就会导致UI重叠。
修复方案
在自定义PropertyDrawer中重写GetPropertyHeight方法,返回属性实际需要的绘制高度,修改后的绘制器代码如下:
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; int index = System.Convert.ToInt32(property.propertyPath.Substring(property.propertyPath.IndexOf("[")).Replace("[", "").Replace("]", "")); label.text = enumNames.names[index]; EditorGUI.PropertyField(position, property, label, true); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { // 自动计算包含子属性的完整高度,第三个参数传true表示包含展开的子元素 return EditorGUI.GetPropertyHeight(property, label, true); } }
重写后Unity会正确获取数组元素展开后的总高度,自动为元素预留足够显示空间,不会再和下方UI重叠。
内容的提问来源于stack exchange,提问作者Insomnia
相关产品推荐
相关产品推荐

