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

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直接复用了整块属性的原始高度,没有按单行控件高度设置每个字段的绘制区域,会导致控件区域重叠

修复方案

  1. 重写GetPropertyHeight方法,根据当前选中的枚举值,返回属性实际需要的总高度
  2. 逐行绘制控件时,每个控件的高度统一使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:45:33