Expandable Property with PropertyDrawer

I tried to create a custom PropertyDrawer which should change the appearance of the property but still show its sub-properties. So it’s still expandable like every other property (which has sub-properties of course) but has some additional feature.

//Example class
public class SomeClass
{
  public float ValueA; // sub-property of SomeClass
  public float ValueB; // sub-property of SomeClass
}

public class SomeMonoBehaviour
{
  public SomeClass TestClass;
}

Default appearance (if expanded):

  • Test Class
    • ValueA
    • ValueB

Desired appearance (if expanded):

  • Test Class + some custom string
    • ValueA
    • ValueB
    • some other custom stuff (for example a button)

Sorry, but I don’t know how to indent the sub-properties correctly.

Now my problem: If I create a custom PropertyDrawer for SomeClass and use a Foldout to achieve the same design but with some custom stuff added, the sub-properties are drawn over the other properties in SomeMonoBehaviour. It seems like the Editor doesn’t recognize the property’s size and assumes it is still 1 line high. To solve this I tried to override GetPropertyHeight() and return the correct height but then if I select the property in the Editor, it selects the whole area (the property and all its sub-properties are highlighted blue). I want it to behave exactly like the default view just with the extra stuff.

Your solution with a Foldout and overriding GetPropertyHeight is correct. To avoid having the Foldout display over your sub-properties, you need to reset the height property of position before drawing your Foldout. Like this:

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    position.height = 16f;
    foldout = EditorGUI.Foldout(position, foldout, label);
    //...
}

I am struggling with the same problem. One way is to put the bool into the target class and read it out via FindPropertyRelative.

public class SomeClass
{
    public float ValueA; // sub-property of SomeClass
    public float ValueB; // sub-property of SomeClass
    public bool _editor_foldout;
}

...

// within the PropertyDrawer
SerializedProperty p = property.FindPropertyRelative("_editor_foldout");
if (p.boolValue = GUI.Foldout(position, p.boolValue, ...))
    ...

I don’t like this solution, but it works somewhat…

Edit: Previously, I put the boolean declaration into “#if UNITY_EDITOR”. DO NOT DO THIS. It seems that "Thou must not declare serializable variables within UNITY_EDITOR, because unfortunately, Unity exports the data from a codebase where UNITY_EDITOR is still defined (which seems very unsensible to me. First rule learned though MFC programming: Always export data with the same defines as you will import them later.)