You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity中自定义PropertyDrawer后List仍显尺寸栏与下拉框如何解决?

嘿,我来帮你搞定这个Unity Inspector的List自定义显示问题!你遇到的默认下拉框和尺寸字段去不掉的核心原因,是没有完全覆盖Unity默认的List PropertyDrawer行为——只重写OnGUI还不够,还得处理属性高度,并且不能调用默认的绘制逻辑。

关键解决步骤

  1. 补全缺失的属性类:你代码里用了[FormatedList]标记,但没定义对应的Attribute类,这会导致自定义Drawer无法绑定生效。
  2. 重写GetPropertyHeight方法:默认的List会预留固定高度给下拉框和尺寸字段,必须通过这个方法返回你需要的高度(比如自定义内容的高度,或者0来完全隐藏)。
  3. 不要调用base.OnGUI():base方法会触发Unity默认的List绘制逻辑,直接跳过它,完全自定义绘制内容。

修改后的完整代码

1. 定义FormatedListAttribute属性类

using UnityEngine;

// 自定义属性标记,用于绑定到PropertyDrawer
public class FormatedListAttribute : PropertyAttribute
{
    // 这里可以添加你需要的配置参数,比如是否显示标题、元素间距等
}

2. 整理后的CursorChange脚本

using System.Collections.Generic;
using UnityEngine;

public class CursorChange : MonoBehaviour
{
    [FormatedList]
    public List<Texture2D> crosshairs;
    public int crosshairWidth = 64;
    public int crosshairHeight = 64;

    private int selected;
    private Transform myTransform;
    private Camera myCamera;

    void Start()
    {
        myCamera = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        myTransform = transform;
        Cursor.visible = false;
    }

    void OnGUI()
    {
        // 增加空值和索引合法性判断,避免报错
        if (Time.time != 0 && Time.timeScale != 0 && crosshairs != null && selected >= 0 && selected < crosshairs.Count)
        {
            GUI.DrawTexture(
                new Rect(Screen.width * 0.5f - crosshairWidth * 0.5f, 
                        Screen.height * 0.5f - crosshairHeight * 0.5f, 
                        crosshairWidth, crosshairHeight), 
                crosshairs[selected]
            );
        }
    }
}

3. 完善后的自定义PropertyDrawer

using System.Reflection;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(FormatedListAttribute))]
public class FormatedListDrawer : PropertyDrawer
{
    // 重写属性高度计算,完全替换默认List的高度
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        if (!property.isArray) return base.GetPropertyHeight(property, label);

        // 计算自定义显示的总高度:标题行 + 每个元素行 + 按钮行 + 间距
        float totalHeight = EditorGUIUtility.singleLineHeight; // 标题高度
        totalHeight += (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * property.arraySize;
        totalHeight += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing * 2; // 按钮行高度
        return totalHeight;
    }

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // 绝对不要调用base.OnGUI(),否则默认控件会被渲染出来
        if (!property.isArray)
        {
            EditorGUI.PropertyField(position, property, label);
            return;
        }

        // 绘制自定义标题
        Rect titleRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.LabelField(titleRect, label);

        // 绘制每个List元素
        float yOffset = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
        for (int i = 0; i < property.arraySize; i++)
        {
            SerializedProperty element = property.GetArrayElementAtIndex(i);
            Rect elementRect = new Rect(position.x, position.y + yOffset, position.width, EditorGUIUtility.singleLineHeight);
            EditorGUI.PropertyField(elementRect, element, new GUIContent($"Crosshair {i+1}"));
            yOffset += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
        }

        // 自定义添加/删除按钮(可选,根据需求调整)
        Rect addBtnRect = new Rect(position.x, position.y + yOffset, position.width / 2, EditorGUIUtility.singleLineHeight);
        if (GUI.Button(addBtnRect, "Add Crosshair"))
        {
            property.arraySize++;
        }

        Rect removeBtnRect = new Rect(position.x + position.width / 2, position.y + yOffset, position.width / 2, EditorGUIUtility.singleLineHeight);
        if (GUI.Button(removeBtnRect, "Remove Last") && property.arraySize > 0)
        {
            property.arraySize--;
        }
    }

    public static System.Type GetType(SerializedProperty property)
    {
        System.Type parentType = property.serializedObject.targetObject.GetType();
        FieldInfo fi = parentType.GetField(property.propertyPath);
        return fi?.FieldType;
    }
}

效果说明

修改后,原来的默认下拉框和尺寸字段会完全消失,取而代之的是你自定义的List显示样式——每个元素单独一行展示,还附带添加/删除按钮。如果只是想完全隐藏List的默认控件,只需要把GetPropertyHeight返回0,并且OnGUI里什么都不绘制即可。

内容的提问来源于stack exchange,提问作者KaNaDa

火山引擎 最新活动