How can I recreate the Array Inspector element for a custom Inspector GUI?

I've been running into troubles doing this and could use some extra thoughts. Here is the code I have so far.

I have an array stored in a script component named `Enemy`. I access this script component, and display it in my custom Inspector, but I always receive errors that not all elements are initialized.

Essentially, I am getting hung up on the idea of how this works: alt text

How can I get `None (Transform)` to appear in my Inspector instead of an error?

private bool collapsed;
private int arraySize;
private Enemy e;

public override void OnInspectorGUI()
{
    EditorGUIUtility.LookLikeControls();

    e = target as Enemy;

    collapsed = EditorGUILayout.Foldout(collapsed, "Array");
    if (collapsed)
    {
        Rect r = EditorGUILayout.BeginVertical();

        arraySize = EditorGUILayout.IntField

        if (e.array.Length > 0)
        {
            Transform[] temp = new Transform[arraySize];

            e.array.CopyTo(temp, 0);

            e.array = new Transform[arraySize];

            temp.CopyTo(e.array, 0);
        }
        else
            e.array = new Transform[arraySize];

        for (int i = 0; i < arraySize; i++)
        {
            Transform t = e.array*;*
 *t = EditorGUILayout.ObjectField(t.name, t, typeof(Transform)) as Transform;*
 *}*
 *EditorGUILayout.EndVertical();*
 *}*
*}*
*```*

If anyone interested, here’s another example for array in custom editor:
Base class:

   public class RoomItem : MonoBehaviour {
        public Transform[] targetPoints;
    // other data
    }

Custom editor:

[CustomEditor(typeof(RoomItem))]
public class RoomItemEditor : Editor {
	public override void OnInspectorGUI() {
		serializedObject.Update();
		var controller = target as RoomItem;
		EditorGUIUtility.LookLikeInspector();
		SerializedProperty tps = serializedObject.FindProperty ("targetPoints");
		EditorGUI.BeginChangeCheck();
		EditorGUILayout.PropertyField(tps, true);
		if(EditorGUI.EndChangeCheck())
			serializedObject.ApplyModifiedProperties();
		EditorGUIUtility.LookLikeControls();
	// ...
	}
}

For anyone else who is searching for the solution to this, here is working code in Javascript. It doesn't look the same as the built-in array controls, but it works fine.

// MyObject.js
public var ElementsExpand : boolean = true;
public var ElementsSize : int = 1;
public var Elements : Transform[] = new Transform[ElementsSize];


// MyObjectEditor.js - OnInspectorGUI()
target.ElementsExpand = EditorGUILayout.Foldout(target.ElementsExpand, "Transforms");
if(target.ElementsExpand) {
    var x : int = 0;
    target.ElementsSize = EditorGUILayout.IntField("Size", target.ElementsSize);
    if(target.Elements.length != target.ElementsSize) {
        var newArray : Transform[] = new Transform[target.ElementsSize];
        for(x = 0; x < target.ElementsSize; x++) {
            if(target.Elements.length > x) {
                newArray[x] = target.Elements[x];
            }
        }
        target.Elements = newArray;
    }
    for(x = 0; x < target.Elements.length; x++) {
        target.Elements[x] = EditorGUILayout.ObjectField("Element "+x, target.Elements[x], typeof(Transform));
    }
}

This is roughly what DrawDefaultInspector() does:

override def OnInspectorGUI():
    serializedObject.Update()

    EditorGUIUtility.LookLikeInspector()

    myIterator = serializedObject.FindProperty("myArrayField")
    while true:
        myRect = GUILayoutUtility.GetRect(0f, 16f);
        showChildren = EditorGUI.PropertyField(myRect, myIterator)
        break unless myIterator.NextVisible(showChildren)

    serializedObject.ApplyModifiedProperties()

It works like it should with bold font on prefab overrides etc. It also handles undo operations, ‘delete’ operations and ‘shift+delete’ operations as expected. It works with all the kinds of arrays that Unity originally supports. It also looks like the original.

Remember to call EditorGUIUtility.LookLikeControls() after drawing the array.

SerializedProperty property = serializedObject.FindProperty(“myArray”);
EditorGUILayout.PropertyField(property, new GUIContent(“My Array”), true);

Since, EditorGUIUtility.LookLikeInspector() and EditorGUIUtility.LookLikeControls() are now obsolete, here is an alternative.

If you want to mimic the default Array display, try this:

SerializedProperty arrayProp = serializedObject.FindProperty("array");

arrayProp.isExpanded = EditorGUILayout.Foldout(arrayProp.isExpanded, "Array");
if (arrayProp.isExpanded) {
	arrayProp.arraySize = EditorGUILayout.IntField("Size", arrayProp.arraySize);

	for (int i = 0; i < arrayProp.arraySize; ++i) {
		SerializedProperty transformProp = arrayProp.GetArrayElementAtIndex(i);
		EditorGUILayout.PropertyField(transformProp, new GUIContent("Element " + i));
	}
}

To expand on what @Steven Walker posted, Started down this road using the newer List<>. I found that typing things like “-” or leaving a field empty destroys the list (counts as “0” elements), so I wrote this code snip-it in C#. This is just for reference, not a complete solution. I decided it would be more user-friendly to supply +/- buttons per element so things can be inserted or removed. I always hated the default method of just destroying from the end. I might even add up and down buttons just for pure organization use…

Anyway. Here is some code which uses a text field and only changes the size value if an actual number is entered. Also note that this clamps to 0-9 since typing 10 would type a “1” first and destroy the list down to 1 item.

    private string entry;
    
    public override void OnInspectorGUI()
    {
        var script = (FireController)target;

        ...

        // Use a string entry so we can ignore special situations like a "-" or
        //   Empty field until an actual number is typed.
        this.entry = EditorGUILayout.TextField("Size", this.entry);

        // TryParse will set it if it can and never throw an error. 
        int size;
        bool result = System.Int32.TryParse(entry, out size);

        // Protect against typing out of a reasonable range
        //   Can't allow "10" because it would be read as "1" first!
        size = Mathf.Clamp(size, 0, 9);

        // If the user changed the count, add or remove elements
        while (size != script.myList.Count)
        {
            if (size > script._effectsOnTarget.Count)
                script._effectsOnTarget.Add(new MyTYPE());
            else
                script._effectsOnTarget.RemoveAt(script.myList.Count-1);
        }

        // No go through the list and add the EditorGUILayout items
        // ...

    }

For now, @booferei 's answer is right. It works for me.