用于从中派生自定义属性绘制器的基类。使用此基类可为您自己的 Serializable 类或者具有自定义 PropertyAttribute 的脚本变量创建自定义绘制器。
PropertyDrawer 有两种用途:
- 自定义 Serializable 类的每个实例的 GUI。
- 自定义具有自定义 PropertyAttribute 的脚本成员的 GUI。
如果您有自定义的 Serializable 类,可以使用 PropertyDrawer 来控制它在 Inspector 中的外观。
请参考以下脚本示例中的 Serializable 类 Ingredient:
using System; using UnityEngine;
public enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class [Serializable] public class Ingredient { public string name; public int amount = 1; public IngredientUnit unit; }
public class Recipe : MonoBehaviour { public Ingredient potionResult; public Ingredient[] potionIngredients; }
可以使用自定义 PropertyDrawer 来更改 Inspector 中 Ingredient 类的每个外观。
您可以使用 CustomPropertyDrawer 特性将 PropertyDrawer 附加到 Serializable 类,然后传入绘制器所对应的 Serializable 类的类型。
可以使用 UIElements 构建自定义 PropertyDrawer,也可以使用 IMGUI。若要使用 UIElements 创建自定义 PropertyDrawer,必须对 PropertyDrawer 类重写 PropertyDrawer.PropertyDrawer。若要使用 IMGUI 创建自定义 PropertyDrawer,必须对 PropertyDrawer 类重写 PropertyDrawer.OnGUI。
如果在基于 UIElements 的检查器或 EditorWindow 内使用 PropertyDrawer,则在任何 IMGUI 实现上使用回退覆盖 PropertyDrawer.PropertyDrawer 时,将使用 UIElements 实现。如果在基于 IMGUI 的检查器或 EditorWindow 内使用 PropertyDrawer,则将仅显示 IMGUI 实现。UIElements 无法在 IMGUI 内运行。
以下是使用 UIElements 写入的自定义 PropertyDrawer 的示例:
using UnityEditor; using UnityEditor.UIElements; using UnityEngine.UIElements;
// IngredientDrawerUIE [CustomPropertyDrawer(typeof(Ingredient))] public class IngredientDrawerUIE : PropertyDrawer { public override VisualElement CreatePropertyGUI(SerializedProperty property) { // Create property container element. var container = new VisualElement();
// Create property fields. var amountField = new PropertyField(property.FindPropertyRelative("amount")); var unitField = new PropertyField(property.FindPropertyRelative("unit")); var nameField = new PropertyField(property.FindPropertyRelative("name"), "Fancy Name");
// Add fields to the container. container.Add(amountField); container.Add(unitField); container.Add(nameField);
return container; } }
以下是使用 IMGUI 写入的自定义 PropertyDrawer 的示例:比较不带有和带有自定义 PropertyDrawer 的 Inspector 中 Ingredient 属性的外观:
\
不带有(左)和带有(右)自定义 PropertyDrawer 的 Inspector 中的类。
using UnityEditor; using UnityEngine;
// IngredientDrawer [CustomPropertyDrawer(typeof(Ingredient))] public class IngredientDrawer : PropertyDrawer { // Draw the property inside the given rect public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Using BeginProperty / EndProperty on the parent property means that // prefab override logic works on the entire property. EditorGUI.BeginProperty(position, label, property);
// Draw label position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0;
// Calculate rects var amountRect = new Rect(position.x, position.y, 30, position.height); var unitRect = new Rect(position.x + 35, position.y, 50, position.height); var nameRect = new Rect(position.x + 90, position.y, position.width - 90, position.height);
// Draw fields - passs GUIContent.none to each so they are drawn without labels EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("amount"), GUIContent.none); EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("unit"), GUIContent.none); EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none);
// Set indent back to what it was EditorGUI.indentLevel = indent;
EditorGUI.EndProperty(); } }
PropertyDrawer 的另一用途是改变脚本中具有自定义 PropertyAttribute 的成员的外观。 假如您要将脚本中的浮点数或整数限制在特定范围内,并在 Inspector 中将其显示为滑动条。 那么,您可以使用内置的 PropertyAttribute(名为 RangeAttribute)来执行此操作:
using UnityEngine; using System.Collections;
public class ExampleClass : MonoBehaviour { // Show this float in the Inspector as a slider between 0 and 10 [Range(0.0F, 10.0F)] public float myFloat = 0.0F; }
您还可以创建自己的 PropertyAttribute。我们将以 RangeAttribute 的代码为例。 该特性必须扩展 PropertyAttribute 类。如果需要,属性可以使用参数并将它们存储为公共成员变量。
// This is not an editor script. The property attribute class should be placed in a regular script file. using UnityEngine;
public class RangeAttribute : PropertyAttribute { public float min; public float max;
public RangeAttribute(float min, float max) { this.min = min; this.max = max; } }
拥有该特性后,需要创建一个 PropertyDrawer 来绘制具有该特性的属性。 绘制器必须扩展 PropertyDrawer 类,且必须具有 CustomPropertyDrawer 特性来说明绘制器所对应的特性。下面是使用 IMGUI 的示例:
// The property drawer class should be placed in an editor script, inside a folder called Editor.
// Tell the RangeDrawer that it is a drawer for properties with the RangeAttribute. using UnityEngine; using UnityEditor;
[CustomPropertyDrawer(typeof(RangeAttribute))] public class RangeDrawer : PropertyDrawer { // Draw the property inside the given rect public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // First get the attribute since it contains the range for the slider RangeAttribute range = attribute as RangeAttribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer. if (property.propertyType == SerializedPropertyType.Float) EditorGUI.Slider(position, property, range.min, range.max, label); else if (property.propertyType == SerializedPropertyType.Integer) EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label); else EditorGUI.LabelField(position, label.text, "Use Range with float or int."); } }
请注意,出于性能原因,EditorGUILayout 函数不能用于 PropertyDrawer。
另请参阅:PropertyAttribute 类、CustomPropertyDrawer 类。
CanCacheInspectorGUI | 重载此方法可确定您的属性的检视面板 GUI 是否可以缓存。 |
GetPropertyHeight | 重载此方法可指定此字段的 GUI 的高度(以像素为单位)。 |
OnGUI | 重写此方法,为属性创建自己的基于 IMGUI 的 GUI。 |