Display A List<Class> With A Custom Editor Script

This example will attempt to show you how to display any List<> array in the inspector when using a custom editor script with a few options. I pieced this together thorough various vaguely explained topics. I have tried to write this in general terms so it can be easily adapted to your needs.

Lets say you have a List you want to be represented by a custom class inside of a custom inspector.

//Script name : CustomList.js
import System; // Import the system class to give us access to List<>

//This is our custom class with our variables
class MyClass{
var AnGO : GameObject;
var AnInt : int;
var AnFloat : float;
var AnVect3 : Vector3;
}

//This is our list we want to use to represent our class as an array.
var MyList : List.<MyClass> = new List.<MyClass>(0); // <-- We need to set an initial length for our list size or the editor will freak out

function AddNew(){
//Add a new index position to the end of our list
MyList.Add(new MyClass());
}

function Remove(index : int){
//Remove an index position from our list at a point in our list array
MyList.RemoveAt(index);
}

Because we hate the way the default inspector presents all our data lets create a custom editor for our inspector.

O Nooo!! Unity does not support displaying LIST ARRRG!

The work around....

This example will show you how to display a list<> via two methods, size the list by defining a size with an int, add a new item to the list with a button, and remove any item from the list by it's index position with a button.

@CustomEditor (CustomList)

class CustomListEditor extends Editor {
    enum displayFieldType {DisplayAsAutomaticFields, DisplayAsCustomizableGUIFields}
    var DisplayFieldType : displayFieldType;

    var GetTarget : SerializedObject;
    var ThisList : SerializedProperty;
    var ListSize : int;

    function OnEnable(){
        GetTarget = new SerializedObject(target);
        ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a refrence of it
    }

    function OnInspectorGUI () {
        //Update our list

        GetTarget.Update();

        //Choose how to display the list<> Example purposes only
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        DisplayFieldType = EditorGUILayout.EnumPopup("",DisplayFieldType);

        //Resize our list
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        EditorGUILayout.LabelField("Define the list size with a number");
        ListSize = ThisList.arraySize;
        ListSize = EditorGUILayout.IntField ("List Size", ListSize);

        if(ListSize != ThisList.arraySize){
            while(ListSize > ThisList.arraySize){
                ThisList.InsertArrayElementAtIndex(ThisList.arraySize);
            }
            while(ListSize < ThisList.arraySize){
                ThisList.DeleteArrayElementAtIndex(ThisList.arraySize - 1);
            }
        }

    EditorGUILayout.Space ();
    EditorGUILayout.Space ();
    EditorGUILayout.LabelField("Or");
    EditorGUILayout.Space ();
    EditorGUILayout.Space ();

    //Or add a new item to the List<> with a button
    EditorGUILayout.LabelField("Add a new item with a button");

    if(GUILayout.Button("Add New")){
        target.MyList.Add(new MyClass());
    }

    EditorGUILayout.Space ();
    EditorGUILayout.Space ();

    //Display our list to the inspector window

    for(var i : int = 0; i < ThisList.arraySize; i++){
        var MyListRef : SerializedProperty = ThisList.GetArrayElementAtIndex(i);
        var MyInt : SerializedProperty = MyListRef.FindPropertyRelative("AnInt");
        var MyFloat : SerializedProperty = MyListRef.FindPropertyRelative("AnFloat");
        var MyVect3 : SerializedProperty = MyListRef.FindPropertyRelative("AnVect3");
        var MyGO : SerializedProperty = MyListRef.FindPropertyRelative("AnGO");


        // Display the property fields in two ways.

        if(DisplayFieldType == 0){// Choose to display automatic or custom field types. This is only for example to help display automatic and custom fields.
            //1. Automatic, No customization <-- Choose me I'm automatic and easy to setup
            EditorGUILayout.LabelField("Automatic Field By Property Type");
            EditorGUILayout.PropertyField(MyGO);
            EditorGUILayout.PropertyField(MyInt);
            EditorGUILayout.PropertyField(MyFloat);
            EditorGUILayout.PropertyField(MyVect3);
        }else{
            //Or

            //2 : Full custom GUI Layout <-- Choose me I can be fully customized with GUI options.
            EditorGUILayout.LabelField("Customizable Field With GUI");
            MyGO.objectReferenceValue = EditorGUILayout.ObjectField("My Custom Go", MyGO.objectReferenceValue, GameObject, true);
            MyInt.intValue = EditorGUILayout.IntField("My Custom Int",MyInt.intValue);
            MyFloat.floatValue = EditorGUILayout.FloatField("My Custom Float",MyFloat.floatValue);
            MyVect3.vector3Value = EditorGUILayout.Vector3Field("My Custom Vector 3",MyVect3.vector3Value);
        }

        EditorGUILayout.Space ();

        //Remove this index from the List
        EditorGUILayout.LabelField("Remove an index from the List<> with a button");
        if(GUILayout.Button("Remove This Index (" + i.ToString() + ")")){
            ThisList.DeleteArrayElementAtIndex(i);
        }
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
    }

    //Apply the changes to our list
    GetTarget.ApplyModifiedProperties();
    }
}

Here is the C# version. This version also describes how to use arrays inside of Class List.

//Script name : CustomList.cs
using UnityEngine;
using System;
using System.Collections.Generic; // Import the System.Collections.Generic class to give us access to List<>

public class CustomList : MonoBehaviour {

    //This is our custom class with our variables
    [System.Serializable]
    public class MyClass{
        public GameObject AnGO;
        public int AnInt;
        public float AnFloat;
        public Vector3 AnVector3;
        public int[] AnIntArray = new int[0];
    }

    //This is our list we want to use to represent our class as an array.
    public List<MyClass> MyList = new List<MyClass>(1);


    void AddNew(){
        //Add a new index position to the end of our list
        MyList.Add(new MyClass());
    }

    void Remove(int index){
        //Remove an index position from our list at a point in our list array
        MyList.RemoveAt(index);
    }
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;

[CustomEditor(typeof(CustomList))]

public class CustomListEditor : Editor {

    enum displayFieldType {DisplayAsAutomaticFields, DisplayAsCustomizableGUIFields}
    displayFieldType DisplayFieldType;

    CustomList t;
    SerializedObject GetTarget;
    SerializedProperty ThisList;
    int ListSize;

    void OnEnable(){
        t = (CustomList)target;
        GetTarget = new SerializedObject(t);
        ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a refrence of it
    }

    public override void OnInspectorGUI(){
        //Update our list

        GetTarget.Update();

        //Choose how to display the list<> Example purposes only
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        DisplayFieldType = (displayFieldType)EditorGUILayout.EnumPopup("",DisplayFieldType);

        //Resize our list
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        EditorGUILayout.LabelField("Define the list size with a number");
        ListSize = ThisList.arraySize;
        ListSize = EditorGUILayout.IntField ("List Size", ListSize);

        if(ListSize != ThisList.arraySize){
            while(ListSize > ThisList.arraySize){
                ThisList.InsertArrayElementAtIndex(ThisList.arraySize);
            }
            while(ListSize < ThisList.arraySize){
                ThisList.DeleteArrayElementAtIndex(ThisList.arraySize - 1);
            }
        }

        EditorGUILayout.Space ();
        EditorGUILayout.Space ();
        EditorGUILayout.LabelField("Or");
        EditorGUILayout.Space ();
        EditorGUILayout.Space ();

        //Or add a new item to the List<> with a button
        EditorGUILayout.LabelField("Add a new item with a button");

        if(GUILayout.Button("Add New")){
            t.MyList.Add(new CustomList.MyClass());
        }

        EditorGUILayout.Space ();
        EditorGUILayout.Space ();

        //Display our list to the inspector window

        for(int i = 0; i < ThisList.arraySize; i++){
            SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex(i);
            SerializedProperty MyInt = MyListRef.FindPropertyRelative("AnInt");
            SerializedProperty MyFloat = MyListRef.FindPropertyRelative("AnFloat");
            SerializedProperty MyVect3 = MyListRef.FindPropertyRelative("AnVector3");
            SerializedProperty MyGO = MyListRef.FindPropertyRelative("AnGO");
            SerializedProperty MyArray = MyListRef.FindPropertyRelative("AnIntArray");


            // Display the property fields in two ways.

            if(DisplayFieldType == 0){// Choose to display automatic or custom field types. This is only for example to help display automatic and custom fields.
                //1. Automatic, No customization <-- Choose me I'm automatic and easy to setup
                EditorGUILayout.LabelField("Automatic Field By Property Type");
                EditorGUILayout.PropertyField(MyGO);
                EditorGUILayout.PropertyField(MyInt);
                EditorGUILayout.PropertyField(MyFloat);
                EditorGUILayout.PropertyField(MyVect3);

                // Array fields with remove at index
                EditorGUILayout.Space ();
                EditorGUILayout.Space ();
                EditorGUILayout.LabelField("Array Fields");

                if(GUILayout.Button("Add New Index",GUILayout.MaxWidth(130),GUILayout.MaxHeight(20))){
                    MyArray.InsertArrayElementAtIndex(MyArray.arraySize);
                    MyArray.GetArrayElementAtIndex(MyArray.arraySize -1).intValue = 0;
                }

                for(int a = 0; a < MyArray.arraySize; a++){
                    EditorGUILayout.PropertyField(MyArray.GetArrayElementAtIndex(a));
                    if(GUILayout.Button("Remove  (" + a.ToString() + ")",GUILayout.MaxWidth(100),GUILayout.MaxHeight(15))){
                        MyArray.DeleteArrayElementAtIndex(a);
                    }
                }
            }else{
                //Or

                //2 : Full custom GUI Layout <-- Choose me I can be fully customized with GUI options.
                EditorGUILayout.LabelField("Customizable Field With GUI");
                MyGO.objectReferenceValue = EditorGUILayout.ObjectField("My Custom Go", MyGO.objectReferenceValue, typeof(GameObject), true);
                MyInt.intValue = EditorGUILayout.IntField("My Custom Int",MyInt.intValue);
                MyFloat.floatValue = EditorGUILayout.FloatField("My Custom Float",MyFloat.floatValue);
                MyVect3.vector3Value = EditorGUILayout.Vector3Field("My Custom Vector 3",MyVect3.vector3Value);


                // Array fields with remove at index
                EditorGUILayout.Space ();
                EditorGUILayout.Space ();
                EditorGUILayout.LabelField("Array Fields");

                if(GUILayout.Button("Add New Index",GUILayout.MaxWidth(130),GUILayout.MaxHeight(20))){
                    MyArray.InsertArrayElementAtIndex(MyArray.arraySize);
                    MyArray.GetArrayElementAtIndex(MyArray.arraySize -1).intValue = 0;
                }

                for(int a = 0; a < MyArray.arraySize; a++){
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("My Custom Int (" + a.ToString() + ")",GUILayout.MaxWidth(120));
                    MyArray.GetArrayElementAtIndex(a).intValue = EditorGUILayout.IntField("",MyArray.GetArrayElementAtIndex(a).intValue, GUILayout.MaxWidth(100));
                    if(GUILayout.Button("-",GUILayout.MaxWidth(15),GUILayout.MaxHeight(15))){
                        MyArray.DeleteArrayElementAtIndex(a);
                    }
                    EditorGUILayout.EndHorizontal();
                }
            }

            EditorGUILayout.Space ();

            //Remove this index from the List
            EditorGUILayout.LabelField("Remove an index from the List<> with a button");
            if(GUILayout.Button("Remove This Index (" + i.ToString() + ")")){
                ThisList.DeleteArrayElementAtIndex(i);
            }
            EditorGUILayout.Space ();
            EditorGUILayout.Space ();
            EditorGUILayout.Space ();
            EditorGUILayout.Space ();
        }

        //Apply the changes to our list
        GetTarget.ApplyModifiedProperties();
    }
}
26 Likes

ForceX - you're a star. Thanks for posting this. It's exactly what I'm trying to do - show a custom class list in the editor but with sliders/other custom controls for certain elements of the class. Brilliant and thanks again! :-D

Ooh by the way, shouldn't myFloat use a FloatField and not an IntField? Just a thought. Can't wait to finish work now and try this code out!

1 Like

[quote]
Ooh by the way, shouldn't myFloat use a FloatField and not an IntField?
[/quote]
Yup you are correct, thanks for pointing that out :)

As for controlling the list size with a slider you can simply replace the ListSize IntField with the slider variant. I'll add in an example when I get off from work.

1 Like

Ah - got home and tested the code.. unfortunately I'm working in C# and my attempts at converting your Javascript example are throwing up errors, most notably in this part of the code:

SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex (i);     
                                SerializedProperty MyTitle = MyListRef.FindPropertyRelative ("title");          
                                SerializedProperty MyGO = MyListRef.FindPropertyRelative ("GO");                
                                SerializedProperty MyType = MyListRef.FindPropertyRelative ("type");
                                SerializedProperty MyDelay = MyListRef.FindPropertyRelative ("delay");
                                SerializedProperty MyDuration = MyListRef.FindPropertyRelative ("duration");
                                SerializedProperty MyAlpha = MyListRef.FindPropertyRelative ("alpha");

                                EditorGUILayout.LabelField ("Customizable Field With GUI");
                                //MyTitle.stringValue = EditorGUILayout.LabelField ("Tile", MyTitle.stringValue);
                                MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO, GameObject, true);
                                MyType.objectReferenceValue = EditorGUILayout.ObjectField ("Type", MyType.objectReferenceValue, ActionType, true);
                                MyDelay.floatValue = EditorGUILayout.FloatField ("Delay", MyDelay.floatValue);
                                MyDuration.floatValue = EditorGUILayout.FloatField ("Duration", MyDuration.floatValue);
                                MyAlpha.floatValue = EditorGUILayout.FloatField ("Alpha", MyAlpha.floatValue);

It doesn't like this: MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO, GameObject, true);

Keeps saying that the expression denotes a 'type', where a 'variable' , 'value' or 'method group' was expected. Also, it didn't like the MyTitle.stringvalue = EditorGUILayout.LabelField("TTitle", MyTitle.stringValue); line at all - saying something about a void value.

Any ideas?

1 Like

I'm still at work so i cant confirm but you can try this.

The MyGO needs to be set with the objectReferenceValue on both the left and right side of your EditorGUILayout.

//Change this
MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO, GameObject, true);

//To this
MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO.objectReferenceValue , GameObject, true);

As for your string try using a TextField instead of a LabelField.

//Change this
MyTitle.stringValue = EditorGUILayout.LabelField ("Tile", MyTitle.stringValue);

//To this
MyTitle.stringValue = EditorGUILayout.TextField("Tile", MyTitle.stringValue);

//Or
EditorGUILayout.PropertyField(MyTitle);

Thanks for looking at this - sorry to bother you at work! ;-)

The change to TextField worked fine for MyTitle, but I've still got the same error on this line:

MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO.objectReferenceValue, GameObject, true);

This is the error:

Assets/Editor/ActionListEditor.cs(61,155): error CS0119: Expression denotes a type', where avariable', value' ormethod group' was expected

And also:

Assets/Editor/ActionListEditor.cs(61,109): error CS1502: The best overloaded method match for `UnityEditor.EditorGUILayout.ObjectField(string, UnityEngine.Object, System.Type, params UnityEngine.GUILayoutOption[ ])' has some invalid arguments

And:

Assets/Editor/ActionListEditor.cs(61,109): error CS1503: Argument #3' cannot convertobject' expression to type `System.Type'

Because you are using C# i think you have to decalere your GameObject with typeof(GameObject)

MyGO.objectReferenceValue = EditorGUILayout.ObjectField ("GO", MyGO.objectReferenceValue, typeof(GameObject), true);

Yep, that's got it - thanks. One last problem - my custom list has another enum within it (ActionType) which I'm trying to display as an EnumPopup like so :

MyType.objectReferenceValue = (ActionType)EditorGUILayout.EnumPopup ("Type", MyType.objectReferenceValue);

(Tried it with and without (ActionType) before EditorGUILayout... and it still bugs out.

Unity is throwing this error:

type is not a supported pptr value.

I think it's not happy about MyType being a SerializedProperty but referring to an ActionType...? I'm still learning the intricacies of C# variable declarations and types it seems...

*** SORTED ***

Problem sorted. Looked back at some previous code I did to display an Enum that wasn't in a List and adapted it to your code - works fine now. Thanks very much for your help ForceX!! :-D

Hey, I'm trying to convert this to the C# too,

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

[CustomEditor(typeof(CustomList))]

public class CustomListEditor : Editor {
   enum displayFieldType {DisplayAsAutomaticFields, DisplayAsCustomizableGUIFields}

   displayFieldType DisplayFieldType;
   SerializedObject GetTarget;
   SerializedProperty ThisList;
   int ListSize;

   void OnEnable(){
     GetTarget = new SerializedObject(target);
     ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a refrence of it
   }

   public override void OnInspectorGUI () {
     //Update our list

     GetTarget.Update();

     //Choose how to display the list<> Example purposes only
     EditorGUILayout.Space ();
     EditorGUILayout.Space ();
     DisplayFieldType = (displayFieldType)EditorGUILayout.EnumPopup("",DisplayFieldType);

     //Resize our list
     EditorGUILayout.Space ();
     EditorGUILayout.Space ();
     EditorGUILayout.LabelField("Define the list size with a number");
     ListSize = ThisList.arraySize;
     ListSize = EditorGUILayout.IntField ("List Size", ListSize);

     if(ListSize != ThisList.arraySize){
       while(ListSize > ThisList.arraySize){
         ThisList.InsertArrayElementAtIndex(ThisList.arraySize);
       }
       while(ListSize < ThisList.arraySize){
         ThisList.DeleteArrayElementAtIndex(ThisList.arraySize - 1);
       }
     }

     EditorGUILayout.Space ();
     EditorGUILayout.Space ();
     EditorGUILayout.LabelField("Or");
     EditorGUILayout.Space ();
     EditorGUILayout.Space ();

     //Or add a new item to the List<> with a button
     EditorGUILayout.LabelField("Add a new item with a button");

     if(GUILayout.Button("Add New")){
        target.MyList.Add(new MyClass());
     }

     EditorGUILayout.Space ();
     EditorGUILayout.Space ();

     //Display our list to the inspector window

     for(int i = 0; i < ThisList.arraySize; i++){
       SerializedProperty MyListRef  = ThisList.GetArrayElementAtIndex(i);
       SerializedProperty MyInt = MyListRef.FindPropertyRelative("AnInt");
       SerializedProperty MyFloat= MyListRef.FindPropertyRelative("AnFloat");
       SerializedProperty MyVect3= MyListRef.FindPropertyRelative("AnVect3");
       SerializedProperty MyGO = MyListRef.FindPropertyRelative("AnGO");


       // Display the property fields in two ways.

       if(DisplayFieldType == 0){// Choose to display automatic or custom field types. This is only for example to help display automatic and custom fields.
         //1. Automatic, No customization <-- Choose me I'm automatic and easy to setup
         EditorGUILayout.LabelField("Automatic Field By Property Type");
         EditorGUILayout.PropertyField(MyGO);
         EditorGUILayout.PropertyField(MyInt);
         EditorGUILayout.PropertyField(MyFloat);
         EditorGUILayout.PropertyField(MyVect3);
       }else{
         //Or

         //2 : Full custom GUI Layout <-- Choose me I can be fully customized with GUI options.
         EditorGUILayout.LabelField("Customizable Field With GUI");
         MyGO.objectReferenceValue = EditorGUILayout.ObjectField("My Custom Go", MyGO.objectReferenceValue, typeof(GameObject), true);
         MyInt.intValue = EditorGUILayout.IntField("My Custom Int",MyInt.intValue);
         MyFloat.floatValue = EditorGUILayout.FloatField("My Custom Float",MyFloat.floatValue);
         MyVect3.vector3Value = EditorGUILayout.Vector3Field("My Custom Vector 3",MyVect3.vector3Value);
       }

       EditorGUILayout.Space ();

       //Remove this index from the List
       EditorGUILayout.LabelField("Remove an index from the List<> with a button");
       if(GUILayout.Button("Remove This Index (" + i.ToString() + ")")){
         ThisList.DeleteArrayElementAtIndex(i);
       }
       EditorGUILayout.Space ();
       EditorGUILayout.Space ();
       EditorGUILayout.Space ();
       EditorGUILayout.Space ();
     }

     //Apply the changes to our list
     GetTarget.ApplyModifiedProperties();
   }
}

But getting this error:
Assets/Editor/CustomListEditor.cs(57,32): error CS1061: Type UnityEngine.Object' does not contain a definition forMyList' and no extension method MyList' of typeUnityEngine.Object' could be found (are you missing a using directive or an assembly reference?)
Here

     if(GUILayout.Button("Add New")){
        target.MyList.Add(new MyClass());
     }

Can you guys help me with this?

Sorry fo the late reply. I will update this later on today after work with a C# version.

Updated first post with C# versions of the script. The C# also shows how to use arrays inside of your custom Class <>List

Thank you

This little line here:

var MyList : List.<MyClass> = new List.<MyClass>(0); // <-- We need to set an initial length for our list size or the editor will freak out

This fixed 1 year of having an error, that was just there... Thankyou :smile:

Hey sorry for the little necro. I was wondering if you could show an example of how to use a ScriptableObject in this way?

Fantastic friend...Still helping a lot..

Hi ForceFX,

I know this post is now ageing, however it looks to be useful only problem is i am having an issue with one line, not sure if Unity changed something so this no longer works or what.

it’s line 20 of the C# code - Editor Script;

t =(CustomList)target;

Error: The name ‘target’ does not exist in the current context.

Not sure what that’s supposed to be, I do not see any reference in your code to define target.

EDIT: after further comparisons i should state that i am using a EditorWindow instead of Editor as well as public void OnGUI() and not public override void OnInspectorGUI(), and I can’t say I am too familiar with the differences.

I’m wondering if Property drawers were a new thing when this thread was started? - still digging deep into all of this.

Hi Zen,

The "target" is intended for an editor class script. Unfortunately I'm not to familiar with the EditorWindow class.

Have you tried to add the "using UnityEditor" to the top of your script?

Hi, Yeah i have that include… so i’m just trying now to wrap my head around the differences between an Editor & an EditorWindow (which appears to be the best way to go for what i want to do)

Many of the samples and tuts i see relate to editing a script attached to each object while what i am trying to accomplish is a stand alone editor(window) that takes a Parent object, then it will go through all the children and copy the transform data and fill in my custom class with that, then you can view a list of these and as my class has a number of other fields you can set min and max parameters for each and Apply these choices to the original (the purpose being random ranging the output back to the original transform)… a one off change.

Anyway i’ll keep searching (after some sleep - i’m spent after trying bits and pieces of a bunch of different people’s code :stuck_out_tongue: at least i did learn Editor and Editor Window are quite different, i got the feeling you could have an EditorWindow that could hold a list of Editors but i might be hallucinating (it’s probably just a Class but with PropertyDrawers they could be displayed in a list all formatted nicely)…

I should prbably just try your code as is and learn from that :slight_smile: thanks btw.

That's interesting I'm sorry I don't have a quick answer (no unity access atm). I guess when I eventually start working on creating a node editor window I'll have to figure it out.

Hey, I made a small change in your code to be more organized in the UnityEditor :)

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;

[CustomEditor(typeof(CustomList))]

public class CustomListEditor : Editor
{

    enum displayFieldType { DisplayAsAutomaticFields, DisplayAsCustomizableGUIFields }
    displayFieldType DisplayFieldType;

    CustomList t;
    SerializedObject GetTarget;
    SerializedProperty ThisList;
    int ListSize;
    List<bool> toggled = new List<bool>(); // Folded or not
    void OnEnable()
    {
        t = (CustomList)target;
        GetTarget = new SerializedObject(t);
        ThisList = GetTarget.FindProperty("MyList"); // Find the List in our script and create a refrence of it
    }

    public override void OnInspectorGUI()
    {
        //Update our list

        GetTarget.Update();

        //Choose how to display the list<> Example purposes only
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        DisplayFieldType = (displayFieldType)EditorGUILayout.EnumPopup("", DisplayFieldType);

        //Resize our list
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Define the list size with a number");
        ListSize = ThisList.arraySize;
        ListSize = EditorGUILayout.IntField("List Size", ListSize);

        if (ListSize != ThisList.arraySize)
        {
            while (ListSize > ThisList.arraySize)
            {
                ThisList.InsertArrayElementAtIndex(ThisList.arraySize);
            }
            while (ListSize < ThisList.arraySize)
            {
                ThisList.DeleteArrayElementAtIndex(ThisList.arraySize - 1);
            }
        }

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Or");
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //Or add a new item to the List<> with a button
        EditorGUILayout.LabelField("Add a new item with a button");

        if (GUILayout.Button("Add New"))
        {
            t.MyList.Add(new CustomList.MyClass());
        }

        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //Display our list to the inspector window

        for (int i = 0; i < ThisList.arraySize; i++)
        {
            toggled.Add(false); // Initialliazed as false
            SerializedProperty MyListRef = ThisList.GetArrayElementAtIndex(i);
            SerializedProperty MyInt = MyListRef.FindPropertyRelative("AnInt");
            SerializedProperty MyFloat = MyListRef.FindPropertyRelative("AnFloat");
            SerializedProperty MyVect3 = MyListRef.FindPropertyRelative("AnVector3");
            SerializedProperty MyGO = MyListRef.FindPropertyRelative("AnGO");
            SerializedProperty MyArray = MyListRef.FindPropertyRelative("AnIntArray");

            toggled[i] = EditorGUILayout.Foldout(toggled[i], "[" + i +"]"); // Index Foldout
            // Display the property fields in two ways.
            if (toggled[i] == true)
            {
                if (DisplayFieldType == 0)
                {// Choose to display automatic or custom field types. This is only for example to help display automatic and custom fields.
                 //1. Automatic, No customization <-- Choose me I'm automatic and easy to setup
                    EditorGUILayout.LabelField("Automatic Field By Property Type");
                    EditorGUILayout.PropertyField(MyGO);
                    EditorGUILayout.PropertyField(MyInt);
                    EditorGUILayout.PropertyField(MyFloat);
                    EditorGUILayout.PropertyField(MyVect3);

                    // Array fields with remove at index
                    EditorGUILayout.Space();
                    EditorGUILayout.Space();
                    EditorGUILayout.LabelField("Array Fields");

                    if (GUILayout.Button("Add New Index", GUILayout.MaxWidth(130), GUILayout.MaxHeight(20)))
                    {
                        MyArray.InsertArrayElementAtIndex(MyArray.arraySize);
                        MyArray.GetArrayElementAtIndex(MyArray.arraySize - 1).intValue = 0;
                    }

                    for (int a = 0; a < MyArray.arraySize; a++)
                    {
                        EditorGUILayout.PropertyField(MyArray.GetArrayElementAtIndex(a));
                        if (GUILayout.Button("Remove  (" + a.ToString() + ")", GUILayout.MaxWidth(100), GUILayout.MaxHeight(15)))
                        {
                            MyArray.DeleteArrayElementAtIndex(a);
                        }
                    }
                }
                else
                {
                    //Or

                    //2 : Full custom GUI Layout <-- Choose me I can be fully customized with GUI options.
                    EditorGUILayout.LabelField("Customizable Field With GUI");
                    MyGO.objectReferenceValue = EditorGUILayout.ObjectField("My Custom Go", MyGO.objectReferenceValue, typeof(GameObject), true);
                    MyInt.intValue = EditorGUILayout.IntField("My Custom Int", MyInt.intValue);
                    MyFloat.floatValue = EditorGUILayout.FloatField("My Custom Float", MyFloat.floatValue);
                    MyVect3.vector3Value = EditorGUILayout.Vector3Field("My Custom Vector 3", MyVect3.vector3Value);


                    // Array fields with remove at index
                    EditorGUILayout.Space();
                    EditorGUILayout.Space();
                    EditorGUILayout.LabelField("Array Fields");

                    if (GUILayout.Button("Add New Index", GUILayout.MaxWidth(130), GUILayout.MaxHeight(20)))
                    {
                        MyArray.InsertArrayElementAtIndex(MyArray.arraySize);
                        MyArray.GetArrayElementAtIndex(MyArray.arraySize - 1).intValue = 0;
                    }

                    for (int a = 0; a < MyArray.arraySize; a++)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("My Custom Int (" + a.ToString() + ")", GUILayout.MaxWidth(120));
                        MyArray.GetArrayElementAtIndex(a).intValue = EditorGUILayout.IntField("", MyArray.GetArrayElementAtIndex(a).intValue, GUILayout.MaxWidth(100));
                        if (GUILayout.Button("-", GUILayout.MaxWidth(15), GUILayout.MaxHeight(15)))
                        {
                            MyArray.DeleteArrayElementAtIndex(a);
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                }

                EditorGUILayout.Space();

                //Remove this index from the List
                EditorGUILayout.LabelField("Remove an index from the List<> with a button");
                if (GUILayout.Button("Remove This Index (" + i.ToString() + ")"))
                {
                    ThisList.DeleteArrayElementAtIndex(i);
                }
                EditorGUILayout.Space();
                EditorGUILayout.Space();
                EditorGUILayout.Space();
                EditorGUILayout.Space();
            }
        }

        //Apply the changes to our list
        GetTarget.ApplyModifiedProperties();
    }
}

What I changed is that all indexes have a foldout choice, so you can go to the specific index you want to make directly the changes you want.

1 Like