When to choose a custom editor vs. property drawer

Hey,

In order for a particular custom type of mine to be displayed in a custom way, there’s the option to use either a full custom inspector, or to define a new property drawer for this type.

I’d like to know - what are the differences between the two, and how should i decide on what to create for my types ?

2 Likes

I think this should be obvious enough but for sake of clarification I will try to explain it simply,

custom inspectors draw how a class fields should look.
property drawers draw how a property should look.

so if you have a property you want to customize and only that property then just go with property drawers, less work since you only have to tag that property with your custom attribute, without having to create a new editor class every time, for sake of simplicity property drawers are generic meaning they deal with the type, so if you create a property drawer for a string type you can choose to implement it for every string field you define or not using attributes, custom inspectors will draw your class no matter and you will have a hard time referencing a property everytime.

imagine this:

Class A : Monobehaviour
{
[SerializedField]
string myString;
}

Class AClassEditor : Editor
{
A myAClass;

void OnEnable()
{
A = target as A;
void override OnInspectorGUI()
{
A.myString = EditorGUILayout.PropertyDrawer(etc...);
}
}
}

this would be done for every class that contains a string value and that value needs to be drawn the same why, while you can do this :

Class A : MonoBehaviour
{
[customStringDrawerAttribute]
string myCustomString;
}


Class A : MonoBehaviour
{
[customStringDrawerAttribute]
string myCustomString;
}


Class B : MonoBehaviour
{
[customStringDrawerAttribute]
string myCustomString;
}

Class C : MonoBehaviour
{
[customStringDrawerAttribute]
string myCustomString;
}


Class D : MonoBehaviour
{
[customStringDrawerAttribute]
string myCustomString;
}
1 Like

In practical terms, opt for property drawers whenever you can, which is along the same lines @mambo_2 suggested. Even if you have a class with several different variables with their own property drawers, it’s usually better than a custom editor, especially when you add in other attribute tags such as [Space], [Header], etc. You’ll almost certainly end up using at least some of those property drawers elsewhere. This avoids duplicate code. And, if you add a new variable, you don’t need to update a custom editor to be able to see it in the inspector.

I’m a bit late to the party but hopefully someone still reads this =)

I get mambo_2’s example but he’s only talking about using property drawers to create new porperty attributes. But you can also rewrite the appearance of a whole script/class, like they do in the first example on this page: Unity - Scripting API: PropertyDrawer

They even state

And the first one looks to me like it achieves more or less the same a custom editor would (please correct me if I’m wrong).
If I want to define how a whole class is displayed in the inspector, in which case should I be using a custom editor and in which case a property drawer? Is it a matter of taste or is there a good reason to chose one over the other in certain cases?

Thanks a lot!

1 Like

Someone else might have some clever distinction to offer, but to me it just seems like personal preference.

Hey there,

Here is the quick difference between them.

Custom Editor: Used for drawing a UnityEngine.Object class in full.
Property Drawer: Used from drawing a nested class, struct, or Attribute inside of a UnityEngine.Object

*You can also mix and match Editors and Property Drawers if you are using SerializedProperties.

Here is a few other comparisons

Property Drawers work only with Serialized Properties ⇒ Editor Windows can get the instance.
If you have a custom Property Drawer for a class that is not a MonoBehavior or ScriptableObject there is not an easy way to get the instance of the class you are currently editing. With SerializedProperties you can only get the objectReferenceValue back as a UnityEngine.Object which your class will not be.

*They also expose the FieldInfo where you can get the instance but it’s not pretty and not everyone likes using reflection.

Editor Windows can’t easily be reused ⇒ Property Drawers can
As people were saying property drawers can be reused all over you code. Editor windows can’t easily be reused since they have to target a class type that inherits from UnityEngine.Object. Property Drawers can target a Attribute or any class.

Property Drawers can’t use the GUILayout system ⇒ Editor Windows can
For performance reasons the Property Drawer can not use the GUILayout system. You are sent a Rect and you have to layout the editor yourself. An Editor Window can take full advantage of this system (which can save time).

You can’t really save local variables with Property Drawers ⇒ Custom Editor you can
When you see your Custom Editor you are looking at an instance that Unity creates for you. You can modify this and save variables but once you look away from the Editor it’s disposed.

Property Drawers work a little bit differently. Lets say you have four public variables that have a custom Property Drawer. Unity creates one instance to draw all of them, it just reuses the same instance (this is why you are sent the serialized property with both it’s functions). This means if you set a variable it’s shared with all of the property drawers. This can be a very big limitation if you are trying to be fancy.

I hope that helps clear up some details.

Cheers,

20 Likes

This thread was extremely helpful!

I myself was a bit confused on the difference and all the answers above were excellent. Especially @BMayne breakdown.

Thanks!

Bleh, I try to use attributes when I can. I think its just neater.

But I use custom editor when I need to use the .FindPropertyRelative(…) from the sterilized property. (in my case I have a custom drawer, which data links multiple objects), something that isn’t possible with attributes

@BMayne your answer is great; reading it again now, i find the term “editor windows” confusing, since you can also create editor windows in Unity (e.g: derive from EditorWindow), not to be confused with custom editors (e.g: inspectors).

2 Likes

Another thing to remember is that you can’t use property drawers to draw an entire collection (List, array). In the case of a collection, OnGUI() in your property drawer will be called once per element in the collection, and the standard GUI will be drawn around it.

@BinaryCats - you can access other properties from a drawer, SerializedProperty has a field for serializedObject, that will return the object that contains the property, and you can use that reference to access sibling SerializedProperties.

@skalev

correct me if I am wrong
You can access the fields in the attribute. Not of the class using the attribute, iirc it errors saying it doesn’t know the instance it is being used in. i.e.

RangeAttribute range = attribute as RangeAttribute;
range.max....

But you cant manipulate varibles in the thing using (in this case the) Range attribute.

Custom editors cant directly do it either, but atleast with a custom editor you create an object, which you can manipulate.


Holy Smokes, I take that back, I misread. I was trying to get the relatives from the property, I didn’t know about the object thanks.

For any that might come across this:

range.m_bool = EditorGUI.Toggle(boolrect, range.m_bool);//Store the tickbox value

if (range.m_bool != oldValue)//Check if it has changed from the last draw
{

property.serializedObject.FindProperty(range.m_text).boolValue = !property.serializedObject.FindProperty(range.m_text).boolValue;// Change the relative's value

oldValue = range.m_bool;
 //store this so we can check if it has changed,
}

Thanks a lot. This has opened up many possibilities for me now.

1 Like

I want to add my five cents, because I didn’t find this information upper.
If we compare the Drawer solution for a specific field (type) in an Inspector based on a “CustomEditor or PropertyDrawer”, the main differences (and different uses) will be:

  • In case the "PropertyDrawer" the can write Drawer for Type (Class) only which not derived from MonoBehaviour or ScriptableObject you must create “Clean C# Data Class” (or use a standard Types that is possible, but doesn’t make a lot of sense)
  • In case the “CustomEditor” we can also write Drawer to any Custom Class (include typical MonoBehaviour scripts etc.)

Also the “PropertyDrawer” only give possibility to change appearance & acting in Inspector (OnGUI / CreatePropertyGUI), the “CustomEditor” also can possibility to change appearance & acting in Scene View (OnInspectorGUI and OnSceneGUI and many others).

The simple Example use both variants together:
Exist Custom Type (“Class”) CameraMode and “MonoBehaviour Class” LookAtPoint. In Scene One GameObject with script LookAtPoint (the both “drawers” in any directory named the Editor)

using UnityEngine;

public enum CameraMode : byte
{
    LockedOn,
    LookAt,
    Free
}

public class LookAtPoint : MonoBehaviour
{
    [SerializeField] private Transform Target;
    [SerializeField] private CameraMode CamMode;

    public Vector3 PositionTarget => Target.position;

    void Update()
    {
        transform.LookAt(Target);
    }

    public void UpdatePositionTarget(Vector3 newPostiion)
    {
        Target.position = newPostiion;
        Update();
    }
}

Simple Drawer for CameraMode (only change label before field in Inspector)

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(CameraMode))]
public class CameraModeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, null, property);
        EditorGUI.PropertyField(position, property, new GUIContent("Mode of Cam"));
        EditorGUI.EndProperty();
    }
}

And Drawer for LookAtPoint also very simple only change order of fields in Inspector and also add functionality to Scene View

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(LookAtPoint))]
public class LookAtPointEditor : Editor
{
    SerializedProperty lookAtPoint;
    SerializedProperty camMode;

    void OnEnable()
    {
        lookAtPoint = serializedObject.FindProperty("Target");
        camMode = serializedObject.FindProperty("CamMode");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        EditorGUILayout.PropertyField(camMode);
        EditorGUILayout.PropertyField(lookAtPoint);
        serializedObject.ApplyModifiedProperties();
    }

    public void OnSceneGUI()
    {
        LookAtPoint t = (target as LookAtPoint);
        EditorGUI.BeginChangeCheck();
        Vector3 pos = Handles.PositionHandle(new Vector3(t.PositionTarget.x, t.PositionTarget.y, t.PositionTarget.z), Quaternion.identity);
        if (EditorGUI.EndChangeCheck())
        {
            Undo.RecordObject(t.Target, "Move point");
            t.UpdatePositionTarget(new Vector3(pos.x, pos.y, pos.z));
        }
    }
}

P.S> The Property Attributes is a more universal PropertyDrawer (it give many useful possibilities but you must design it more careful because the attribute can set to any field type). @BMayne and other wrote many useful, but more detail

2 Likes