当前位置:   article > 正文

Unity Editor 编辑器拓展 10——PropertyDrawer 属性绘制器

propertydrawer

描述

用于从中派生自定义属性绘制器的基类。使用此基类可为您自己的 Serializable 类或者具有自定义 PropertyAttribute 的脚本变量创建自定义绘制器。

PropertyDrawer 有两种用途:
- 自定义 Serializable 类的每个实例的 GUI。
- 自定义具有自定义 PropertyAttribute 的脚本成员的 GUI。

如果您有自定义的 Serializable 类,可以使用 PropertyDrawer 来控制它在 Inspector 中的外观。 请参考以下脚本示例中的 Serializable 类 Ingredient:

  1. using System;
  2. using UnityEngine;
  3. public enum IngredientUnit { Spoon, Cup, Bowl, Piece }
  4. // Custom serializable class
  5. [Serializable]
  6. public class Ingredient
  7. {
  8. public string name;
  9. public int amount = 1;
  10. public IngredientUnit unit;
  11. }
  12. public class Recipe : MonoBehaviour
  13. {
  14. public Ingredient potionResult;
  15. public Ingredient[] potionIngredients;
  16. }

使用 PropertyDrawer 可以更改每个 Ingredient 类在 Inspector 中的外观。 比较不带和带有自定义 PropertyDrawer 的 Inspector 中 Ingredient 属性的外观:

不带有(左)和带有(右)自定义 PropertyDrawer 的 Inspector 中的类。

您可以使用 CustomPropertyDrawer 特性将 PropertyDrawer 附加到 Serializable 类,然后传入绘制器所对应的 Serializable 类的类型。

  1. using UnityEditor;
  2. using UnityEngine;
  3. // IngredientDrawer
  4. [CustomPropertyDrawer(typeof(Ingredient))]
  5. public class IngredientDrawer : PropertyDrawer
  6. {
  7. // Draw the property inside the given rect
  8. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  9. {
  10. // Using BeginProperty / EndProperty on the parent property means that
  11. // prefab override logic works on the entire property.
  12. EditorGUI.BeginProperty(position, label, property);
  13. // Draw label
  14. position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
  15. // Don't make child fields be indented
  16. var indent = EditorGUI.indentLevel;
  17. EditorGUI.indentLevel = 0;
  18. // Calculate rects
  19. var amountRect = new Rect(position.x, position.y, 30, position.height);
  20. var unitRect = new Rect(position.x + 35, position.y, 50, position.height);
  21. var nameRect = new Rect(position.x + 90, position.y, position.width - 90, position.height);
  22. // Draw fields - passs GUIContent.none to each so they are drawn without labels
  23. EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("amount"), GUIContent.none);
  24. EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("unit"), GUIContent.none);
  25. EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none);
  26. // Set indent back to what it was
  27. EditorGUI.indentLevel = indent;
  28. EditorGUI.EndProperty();
  29. }
  30. }

PropertyDrawer 的另一用途是改变脚本中具有自定义 PropertyAttribute 的成员的外观。 假如您要将脚本中的浮点数或整数限制在特定范围内,并在 Inspector 中将其显示为滑动条。 那么,您可以使用内置的 PropertyAttribute(名为 RangeAttribute)来执行此操作:

  1. using UnityEngine;
  2. using System.Collections;
  3. public class ExampleClass : MonoBehaviour
  4. {
  5. // Show this float in the Inspector as a slider between 0 and 10
  6. [Range(0.0F, 10.0F)]
  7. public float myFloat = 0.0F;
  8. }

您还可以创建自己的 PropertyAttribute。我们将以 RangeAttribute 的代码为例。 该特性必须扩展 PropertyAttribute 类。如果需要,属性可以使用参数并将它们存储为公共成员变量。

  1. // This is not an editor script. The property attribute class should be placed in a regular script file.
  2. using UnityEngine;
  3. public class RangeAttribute : PropertyAttribute
  4. {
  5. public float min;
  6. public float max;
  7. public RangeAttribute(float min, float max)
  8. {
  9. this.min = min;
  10. this.max = max;
  11. }
  12. }

拥有该特性后,您需要创建一个 PropertyDrawer 来绘制具有该特性的属性。 绘制器必须扩展 PropertyDrawer 类,且必须具有 CustomPropertyDrawer 特性来说明绘制器所对应的特性。

  1. // The property drawer class should be placed in an editor script, inside a folder called Editor.
  2. // Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute.
  3. using UnityEngine;
  4. using UnityEditor;
  5. [CustomPropertyDrawer(typeof(RangeAttribute))]
  6. public class RangeDrawer : PropertyDrawer
  7. {
  8. // Draw the property inside the given rect
  9. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  10. {
  11. // First get the attribute since it contains the range for the slider
  12. RangeAttribute range = attribute as RangeAttribute;
  13. // Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
  14. if (property.propertyType == SerializedPropertyType.Float)
  15. EditorGUI.Slider(position, property, range.min, range.max, label);
  16. else if (property.propertyType == SerializedPropertyType.Integer)
  17. EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label);
  18. else
  19. EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
  20. }
  21. }

请注意,出于性能原因,EditorGUILayout 函数不能用于 PropertyDrawer。

另请参阅:PropertyAttribute 类、CustomPropertyDrawer 类。

变量

attribute此属性的 PropertyAttribute。不适用于自定义类绘制器。(只读)
fieldInfo此属性所表示的成员的反射 FieldInfo。(只读)

公共函数

CanCacheInspectorGUI重载此方法可确定您的属性的检视面板 GUI 是否可以缓存。
GetPropertyHeight重载此方法可指定此字段的 GUI 的高度(以像素为单位)。
OnGUI重写此方法,以针对该属性创建您自己的 GUI。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/100948?site
推荐阅读
相关标签
  

闽ICP备14008679号