Unity自定义PropertyDrawer滚动触发System.ArgumentException问题求助
解决Inspector滚动时自定义PropertyDrawer的ArgumentException错误
核心问题定位
这个错误通常是因为滚动时被遮挡字段的序列化对象引用失效,或是绘制属性时未正确处理SerializedProperty的有效性、可见性状态。比如对象移出视口后,Unity可能临时释放部分序列化数据引用,此时直接访问property.objectReferenceValue或其属性就会触发参数异常。
具体修复步骤
1. 严格校验SerializedProperty及引用对象有效性
在OnGUI方法开头就做有效性检查,避免无效访问:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // 校验核心对象有效性 if (property == null || property.propertyType != SerializedPropertyType.ObjectReference) { EditorGUI.LabelField(position, label, new GUIContent("Invalid object reference field")); return; } var targetObj = property.objectReferenceValue; if (targetObj == null) { EditorGUI.ObjectField(position, property, label); return; } // 后续绘制逻辑放在此处 }
2. 使用SerializedObject处理目标对象属性
不要直接通过反射访问目标对象属性,而是将其包装成SerializedObject,借助Unity序列化系统处理绘制,避免状态不一致:
// 替换直接反射的逻辑 var serializedTarget = new SerializedObject(targetObj); serializedTarget.Update(); // 获取Attribute指定的要显示的属性 var displayProps = attribute as DisplayPropertiesAttribute; foreach (var propName in displayProps.PropertyNames) { var childProp = serializedTarget.FindProperty(propName); if (childProp != null) { position.height = EditorGUI.GetPropertyHeight(childProp); EditorGUI.PropertyField(position, childProp); position.y += position.height + EditorGUIUtility.standardVerticalSpacing; } } serializedTarget.ApplyModifiedProperties();
3. 用BeginProperty/EndProperty维护字段状态
Unity滚动时依赖这对方法维护字段状态,必须包裹整个绘制逻辑:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); // 上述校验与绘制逻辑放在此处 EditorGUI.EndProperty(); }
4. 重写GetPropertyHeight时也要做有效性校验
自定义高度计算时,同样要检查对象有效性,避免返回错误高度导致布局混乱:
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (property == null || property.objectReferenceValue == null) { return EditorGUI.GetPropertyHeight(property, label); } var serializedTarget = new SerializedObject(property.objectReferenceValue); var displayProps = attribute as DisplayPropertiesAttribute; float totalHeight = EditorGUI.GetPropertyHeight(property, label) + EditorGUIUtility.standardVerticalSpacing; foreach (var propName in displayProps.PropertyNames) { var childProp = serializedTarget.FindProperty(propName); if (childProp != null) { totalHeight += EditorGUI.GetPropertyHeight(childProp) + EditorGUIUtility.standardVerticalSpacing; } } return totalHeight - EditorGUIUtility.standardVerticalSpacing; // 移除最后一个多余间距 }
数组显示问题临时处理(可选)
如果数组显示异常,确保用EditorGUI.PropertyField绘制数组元素,并分配正确的Rect区域:
// 数组属性绘制示例 if (childProp.isArray) { position.height = EditorGUI.GetPropertyHeight(childProp); EditorGUI.PropertyField(position, childProp, true); // 第二个参数true表示展开数组 position.y += position.height + EditorGUIUtility.standardVerticalSpacing; }
内容的提问来源于stack exchange,提问作者Mofrison
相关产品推荐
相关产品推荐

