The way I should do that is by making a custom inspector.
Since Unity 4.5 There is this class called UnityEditorInternal.ReorderableList. Sadly it is not documented, but it is a very nice class. (The result should be compareable to your list)
This is a class that can be used to draw a list in the inspector the way Unity draws some of it’s own lists (Like the list used to add sorting layers for instance)
Since you are talking about serializable objects, I assume you are talking about classes that have the Serializable attribute, and not MonoBehaviours that are serializable by default.
To implement this you need a Class that is Serializable (Or MonoBehaviour)
using UnityEngine;
using System;
[Serializable]
public class ListItemExample
{
public bool boolValue;
public string stringvalue;
}
Then you need the MonoBehaviour that has a list you want to show in the inspector
using UnityEngine;
using System.Collections.Generic;
public class ListExample : MonoBehaviour
{
[HideInInspector] // we do this beacause we call base.OnInspectorGUI(); And we don't want that to draw the list aswell.
public List<ListItemExample> list;
}
And then the place where the magic happens. The custom inspector.
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
[CustomEditor(typeof(ListExample))]
public class listExampleInspector : Editor
{
private ReorderableList reorderableList;
private ListExample listExample
{
get
{
return target as ListExample;
}
}
private void OnEnable()
{
reorderableList = new ReorderableList(listExample.list,typeof(ListItemExample), true, true, true, true);
// This could be used aswell, but I only advise this your class inherrits from UnityEngine.Object or has a CustomPropertyDrawer
// Since you'll find your item using: serializedObject.FindProperty("list").GetArrayElementAtIndex(index).objectReferenceValue
// which is a UnityEngine.Object
// reorderableList = new ReorderableList(serializedObject, serializedObject.FindProperty("list"), true, true, true, true);
// Add listeners to draw events
reorderableList.drawHeaderCallback += DrawHeader;
reorderableList.drawElementCallback += DrawElement;
reorderableList.onAddCallback += AddItem;
reorderableList.onRemoveCallback += RemoveItem;
}
private void OnDisable()
{
// Make sure we don't get memory leaks etc.
reorderableList.drawHeaderCallback -= DrawHeader;
reorderableList.drawElementCallback -= DrawElement;
reorderableList.onAddCallback -= AddItem;
reorderableList.onRemoveCallback -= RemoveItem;
}
/// <summary>
/// Draws the header of the list
/// </summary>
/// <param name="rect"></param>
private void DrawHeader(Rect rect)
{
GUI.Label(rect, "Our fancy reorderable list");
}
/// <summary>
/// Draws one element of the list (ListItemExample)
/// </summary>
/// <param name="rect"></param>
/// <param name="index"></param>
/// <param name="active"></param>
/// <param name="focused"></param>
private void DrawElement(Rect rect, int index, bool active, bool focused)
{
ListItemExample item = listExample.list[index];
EditorGUI.BeginChangeCheck();
item.boolValue = EditorGUI.Toggle(new Rect(rect.x, rect.y, 18, rect.height), item.boolValue);
item.stringvalue = EditorGUI.TextField(new Rect(rect.x + 18, rect.y, rect.width - 18, rect.height), item.stringvalue);
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(target);
}
// If you are using a custom PropertyDrawer, this is probably better
// EditorGUI.PropertyField(rect, serializedObject.FindProperty("list").GetArrayElementAtIndex(index));
// Although it is probably smart to cach the list as a private variable ;)
}
private void AddItem(ReorderableList list)
{
listExample.list.Add(new ListItemExample());
EditorUtility.SetDirty(target);
}
private void RemoveItem(ReorderableList list)
{
listExample.list.RemoveAt(list.index);
EditorUtility.SetDirty(target);
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
// Actually draw the list in the inspector
reorderableList.DoLayoutList();
}
}
This is then how it looks in the editor:

This works even better if you use a CustomPropertyDrawer (for the link: go to the “WRITING A PROPERTYDRAWER FOR A CUSTOM SERIALIZABLE CLASS” part) for you custom Serializable class. Maybe the solution you are using now also works when you use a custompropertydrawer, but I can’t tell for sure because I never used this plugin 