Version: 2017.4
LanguageEnglish
  • C#
  • JS

Script language

Select your preferred scripting language. All code snippets will be displayed in this language.

PropertyDrawer

class in UnityEditor

/

Inherits from:GUIDrawer

Suggest a change

Success!

Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.

Close

Submission failed

For some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.

Close

Cancel

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:

#pragma strict
public enum IngredientUnit {
	Spoon,
	Cup,
	Bowl,
	Piece,
}
// Custom serializable class
@Serializable
public class Ingredient {
	public var name: String;
	public var amount: int = 1;
	public var unit: IngredientUnit;
}
public class PropertyDrawerTestClass extends MonoBehaviour {
	public var potionResult: Ingredient;
	public var potionIngredients: Ingredient[];
}
using System;
using System.Collections;
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 PropertyDrawerTestClass : MonoBehaviour { public Ingredient potionResult; public Ingredient[] potionIngredients; }

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.

#pragma strict
// IngredientDrawer
@CustomPropertyDrawer(Ingredient)
public class IngredientDrawer extends PropertyDrawer {
    // Draw the property inside the given rect
    public override function OnGUI(position: Rect, property: SerializedProperty, label: GUIContent) {
        // 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();
    }
}
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(); } }

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:

#pragma strict
@Range(0.0F, 10.0F)
public var myFloat: float = 0.0F;
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; }

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.

#pragma strict
// This is not an editor script. The property attribute class should be placed in a regular script file.
public class RangeAttribute extends PropertyAttribute {
	public var min: float;
	public var max: float;
	RangeAttributefloatminfloatmax {
		this.min = min;
		this.max = max;
	}
}
// 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; } }

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.

#pragma strict
// 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)
public class RangeDrawer extends PropertyDrawer {
	// Draw the property inside the given rect
	public override 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);
		elseif (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.");
	}
}
// 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."); } }

Note that for performance reasons, EditorGUILayout functions are not usable with PropertyDrawers.

See Also: PropertyAttribute class, CustomPropertyDrawer class.

Properties

attributeThe PropertyAttribute for the property. Not applicable for custom class drawers. (Read Only)
fieldInfoThe reflection FieldInfo for the member this property represents. (Read Only)

Public Methods

CanCacheInspectorGUIOverride this method to determine whether the inspector GUI for your property can be cached.
GetPropertyHeightOverride this method to specify how tall the GUI for this field is in pixels.
OnGUIOverride this method to make your own GUI for the property.

Inherited Members