Unity中自定义PropertyDrawer后List仍显尺寸栏与下拉框如何解决?
嘿,我来帮你搞定这个Unity Inspector的List自定义显示问题!你遇到的默认下拉框和尺寸字段去不掉的核心原因,是没有完全覆盖Unity默认的List PropertyDrawer行为——只重写OnGUI还不够,还得处理属性高度,并且不能调用默认的绘制逻辑。
关键解决步骤
- 补全缺失的属性类:你代码里用了
[FormatedList]标记,但没定义对应的Attribute类,这会导致自定义Drawer无法绑定生效。 - 重写
GetPropertyHeight方法:默认的List会预留固定高度给下拉框和尺寸字段,必须通过这个方法返回你需要的高度(比如自定义内容的高度,或者0来完全隐藏)。 - 不要调用
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




