Creating vertical space for EditorGUI

My problem has to do with using EditorGUI (as opposed to EditorGUILayout because I want pretty strict control over the sizing and positioning of elements). I got the GUI working as I want it, but I can’t figure out how to tell Unity how tall the element as a whole is.

Here’s a screenshot of a ScriptableWizard displaying the SerializedProperty:

pic

I figured out how to cheese the system by adding a bunch of EditorGUILayout blank space at the end based on the height of the UI (ypos is a variable derived from the loops used to generate the interface):

if (Event.current.type == EventType.Layout) {
    EditorGUILayout.BeginVertical();
    for (int i = 0; i < ypos; i += 5) EditorGUILayout.Space();
    EditorGUILayout.EndVertical();
}

pic

However, once Unity tries to display this interface in the inspector instead of a wizard, my cheese method stops working. It displays on top of other elements.

My question is more or less this: What’s the non-cheese way of doing this? Here’s the complete class I’m working with:

[CustomPropertyDrawer(typeof(PuzzleGrid))]
public class PuzzleGridDrawer : PropertyDrawer {
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
        EditorGUI.BeginProperty(position, label, property);

        var indent = EditorGUI.indentLevel;
        EditorGUI.indentLevel = 0;

       //UI Code using EditorGUI and GUI.Button exclusively, hidden because it's like 150 lines and shouldn't be relevant. Let me know if it is and I can include the whole thing.

        EditorGUI.indentLevel = indent;

        EditorGUI.EndProperty();

        if (Event.current.type == EventType.Layout) {
            EditorGUILayout.BeginVertical();
            for (int i = 0; i < ypos; i += 5) EditorGUILayout.Space();
            EditorGUILayout.EndVertical();
        }
    }
}

(I have tried setting position.height directly, but it doesn’t do anything.)

A PropertyDrawer has exactly two method which you can override:

Unity first calls “GetPropertyHeight” of your PropertyDrawer to determine the height of your property. After that it calls OnGUI with the proper position rect that has the requested height.

Maybe i got something wrong about your question, but overriding GetPropertyHeight and providing the correct height should fix your problem. The default property height is 16 pixels. GetPropertyHeight is literally implemented like this:

public virtual float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
    return 16f;
}

So just override the method.

edit
ps: A property drawer should always stay within its position rect. Your code doesn’t show how you actually draw your GUI, but i guess you draw outside the rect.

If you have a dynamic element then you can set the ‘GetPropertyHeight’ to be variable depending on number of children or if it is expanded etc, so the next element will always be directly below it.

Here’s an example of how to determine a list objects height.
Assuming each line is the default height (Which you can get from EditorGUIUtility.singleLineHeight which is 16)

[SerializeField]
ListObject listObj;

[Serializable]
public class ListObject
{
	public List<int> myList = new List<int>();
}

[CustomPropertyDrawer(typeof(ListObject))]
public class ListObjectPropertyDrawer : PropertyDrawer
{
	public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
	{
		float height = base.GetPropertyHeight(property, label);
		SerializedProperty listProperty = property.FindPropertyRelative("myList");
		if(listProperty.isExpanded)
		{
			// foldout and size field + children
			height *= 2 + listProperty.arraySize;
		}

		return height;
	}

	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
	{
		position.height = EditorGUIUtility.singleLineHeight;

		SerializedProperty listProperty = property.FindPropertyRelative("myList");

		listProperty.isExpanded = EditorGUI.Foldout(position, listProperty.isExpanded, label);
		position.y += position.height;
		if(listProperty.isExpanded)
		{
			EditorGUI.indentLevel++;
			listProperty.arraySize = EditorGUI.IntField(position, "Size", listProperty.arraySize);
			position.y += position.height;

			for(int i = 0; i < listProperty.arraySize; i++)
			{
				SerializedProperty element = listProperty.GetArrayElementAtIndex(i);
				EditorGUI.PropertyField(position, element);
				position.y += position.height;
			}
			EditorGUI.indentLevel--;
		}
	}
}