Description
Base class to derive custom property drawers from. Use this to create custom drawers for your own Serializable classes or for script variables with custom PropertyAttributes.
PropertyDrawers have two uses:
- Customize the GUI of every instance of a
Serializable class.
- Customize the GUI of script members with custom
PropertyAttributes.
If you have a custom
Serializable class, you can use a PropertyDrawer to control how it looks in the Inspector.
Consider the Serializable class Ingredient in the script below:
// Recipe.js
// This is not an editor scriptenum IngredientUnit { Spoon, Cup, Bowl, Piece }// Custom serializable class
class Ingredient extends System.Object {
var name : String;
var amount : int = 1;
var unit : IngredientUnit;
}var potionResult : Ingredient;
var potionIngredients : Ingredient[];function Update () {
// Update logic here...
}
using UnityEngine;
using System.Collections;
public class Ingredient : MonoBehaviour {
public string name;
public int amount = 1;
public IngredientUnit unit;
}
public class Example : MonoBehaviour {
public Ingredient potionResult;
public Ingredient[] potionIngredients;
}
import UnityEngine
import System.Collections
public enum IngredientUnit:
Spoon
Cup
Bowl
Piece
public class Ingredient(System.Object):
public name as string
public amount as int = 1
public unit as IngredientUnit
public class Example(MonoBehaviour):
public potionResult as Ingredient
public potionIngredients as (Ingredient)
Using a custom PropertyDrawer, every appearance of the Ingredient class in the Inspector can be changed.
Compare the look of the Ingredient properties in the Inspector without and with a custom PropertyDrawer:
Class in the Inspector without (left) and with (right) custom PropertyDrawer.You can attach the PropertyDrawer to a Serializable class by using the
CustomPropertyDrawer attribute and pass in the type of the Serializable class that it's a drawer for.
// IngredientDrawer.js
@CustomPropertyDrawer (Ingredient)
class IngredientDrawer extends PropertyDrawer {
// Draw the property inside the given rect
function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
// 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 ();
}
}
no example available in C#
no example available in Boo
The other use of PropertyDrawer is to alter the appearance of members in a script that have custom
PropertyAttributes.
Say you want to limit floats or integers in your script to a certain range and show them as sliders in the Inspector.
Using the built-in
PropertyAttribute called
RangeAttribute you can do just that:
// Show this float in the Inspector as a slider between 0 and 10
@Range (0.0, 10.0)
var myFloat = 0.0;
using UnityEngine;
using System.Collections;
public class Example : MonoBehaviour {
[Range(0.0F, 10.0F)]
public float myFloat = 0.0F;
}
import UnityEngine
import System.Collections
public class Example(MonoBehaviour):
[Range(0.0F, 10.0F)]
public myFloat as float = 0.0F
You can make your own
PropertyAttribute as well. We'll use the code for the
RangeAttribute as an example.
The attribute must extend the PropertyAttribute class. If you want, your property can take parameters and store them as public member variables.
// This is not an editor script. The property attribute class should be placed in a regular script file.
class RangeAttribute extends PropertyAttribute {
var min : float;
var max : float;
function RangeAttribute (min : float, max : float) {
this.min = min;
this.max = max;
}
}
Now that you have the attribute, you need to make a PropertyDrawer that draws properties that have that attribute.
The drawer must extend the PropertyDrawer class, and it must have a
CustomPropertyDrawer attribute to tell it which attribute it's a drawer for.
// 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.
@CustomPropertyDrawer (RangeAttribute)
class RangeDrawer extends PropertyDrawer {
// Draw the property inside the given rect
function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
// First get the attribute since it contains the range for the slider
var range : RangeAttribute = 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, range.min, range.max, label);
else
EditorGUI.LabelField (position, label.text, "Use Range with float or int.");
}
}
no example available in C#
no example available in Boo