Unity自定义PropertyDrawer的Inspector面板变量半隐藏显示异常
Unity自定义Inspector枚举控制字段显隐异常修复
问题表现
在Unity Editor开发中,通过自定义PropertyDrawer实现「根据枚举值选择展示对应字段」的逻辑时,枚举选择控件下方的字段无法正常可见,处于半显示半隐藏、被遮挡的异常状态。
原始实现代码如下:
[CustomPropertyDrawer(typeof(QuestGoal))] public class QuestGoal_PropertyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); SerializedProperty questType = property.FindPropertyRelative("questType"); SerializedProperty item = property.FindPropertyRelative("item"); SerializedProperty currentAmount = property.FindPropertyRelative("currentAmount"); SerializedProperty totalAmount = property.FindPropertyRelative("totalAmount"); SerializedProperty positionQuest = property.FindPropertyRelative("positionQuest"); float lineHeight = EditorGUIUtility.singleLineHeight; position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); EditorGUI.PropertyField(position, questType, GUIContent.none); switch (questType.intValue) { case (int)QuestType.CRAFTING: position = new Rect(position.x, position.y + lineHeight, position.width, position.height); EditorGUI.PropertyField(position, item); break; case (int)QuestType.GATHERING: position = new Rect(position.x, position.y + lineHeight, position.width, position.height); EditorGUI.PropertyField(position, currentAmount); position = new Rect(position.x, position.y + lineHeight * 2, position.width, position.height); EditorGUI.PropertyField(position, totalAmount); break; case (int)QuestType.JOURNEY: position = new Rect(position.x, position.y + lineHeight, position.width, position.height); EditorGUI.PropertyField(position, positionQuest); break; default: break; } EditorGUI.EndProperty(); } }
问题根因
- 未重写
GetPropertyHeight方法:Unity默认只为自定义绘制的属性预留单行控件高度,下方额外绘制的字段超出预留高度范围,会被后续其他Inspector控件遮挡,出现半隐半现的效果 - 子控件绘制尺寸错误:代码中为子字段传入的Rect直接复用了整块属性的原始高度,没有按单行控件高度设置每个字段的绘制区域,会导致控件区域重叠
修复方案
- 重写
GetPropertyHeight方法,根据当前选中的枚举值,返回属性实际需要的总高度 - 逐行绘制控件时,每个控件的高度统一使用
EditorGUIUtility.singleLineHeight,行之间预留固定间距避免重叠
修复后的完整代码:
[CustomPropertyDrawer(typeof(QuestGoal))] public class QuestGoal_PropertyDrawer : PropertyDrawer { // 行间距 private const float Padding = 2f; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { SerializedProperty questType = property.FindPropertyRelative("questType"); float lineHeight = EditorGUIUtility.singleLineHeight + Padding; // 基础高度:枚举选择行 float totalHeight = lineHeight; switch (questType.intValue) { case (int)QuestType.CRAFTING: case (int)QuestType.JOURNEY: // 多1行字段 totalHeight += lineHeight; break; case (int)QuestType.GATHERING: // 多2行字段 totalHeight += lineHeight * 2; break; } return totalHeight; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); SerializedProperty questType = property.FindPropertyRelative("questType"); SerializedProperty item = property.FindPropertyRelative("item"); SerializedProperty currentAmount = property.FindPropertyRelative("currentAmount"); SerializedProperty totalAmount = property.FindPropertyRelative("totalAmount"); SerializedProperty positionQuest = property.FindPropertyRelative("positionQuest"); float lineHeight = EditorGUIUtility.singleLineHeight; float currentY = position.y; // 绘制枚举选择行 Rect enumRect = new Rect(position.x, currentY, position.width, lineHeight); enumRect = EditorGUI.PrefixLabel(enumRect, GUIUtility.GetControlID(FocusType.Passive), label); EditorGUI.PropertyField(enumRect, questType, GUIContent.none); currentY += lineHeight + Padding; // 根据枚举值绘制对应字段 switch (questType.intValue) { case (int)QuestType.CRAFTING: Rect itemRect = new Rect(position.x, currentY, position.width, lineHeight); EditorGUI.PropertyField(itemRect, item); break; case (int)QuestType.GATHERING: Rect currentRect = new Rect(position.x, currentY, position.width, lineHeight); EditorGUI.PropertyField(currentRect, currentAmount); currentY += lineHeight + Padding; Rect totalRect = new Rect(position.x, currentY, position.width, lineHeight); EditorGUI.PropertyField(totalRect, totalAmount); break; case (int)QuestType.JOURNEY: Rect posRect = new Rect(position.x, currentY, position.width, lineHeight); EditorGUI.PropertyField(posRect, positionQuest); break; } EditorGUI.EndProperty(); } }
内容的提问来源于stack exchange,提问作者Samuel HOARAU
相关产品推荐
相关产品推荐

