Trying to Create Default List in Custom Inspector

Creating a custom inspector for a tool. In the tool, there is a list of custom objects, and I’m creating a custom inspector for this list. Inside of this custom object, there is another list, and for this nested list I’d like to draw the default list inspector.

To this end, I’ve tried using the FindProperty, and EditorGUILayout.PropertyField method but keep getting the error that “Type ‘CustomObj’ does not contain a definition for ‘FindProperty’”

The CustomObj is Serializable, so I’m not sure where I’ve gone wrong. Sample code below.

Main Class

[Serializable]
public class CustomObj {
  public bool data1 = false;
  public string someString;
  public Transform[] nestedList = new Transform[1];
}

public class SomeTool:MonoBehaviour {
  public CustomObj[] customList = null;
  ...
}

Editor Class

[CustomEditor(typeof(SomeTool))]
class SomeToolEditor:Editor {
  private bool showAll = true;

  public override void OnInspectorGUI() {
    SomeTool script = target as SomeTool;
  
    showAll = EditorGUILayout.Foldout( showAll, "Tools" );
    if (showAll) {
      foreach (CustomObj co in script.customList) {
        EditorGUILayout.PropertyField(co.FindProperty("nestedList"));
      }
    }
  }
}

I’ve tried setting CustomObj to inhereit MonoBehaviour w/ no success as well.

FindProperty is located inside SerializedObject and not MonoBehaviour or System.Object - If you want a relative property, use FindPropertyRelative.

It becomes a bit tricky when you nest and deal with System.Objects via SerializedProperties.

First of all, if you want to draw a list/array you need to pass true to PropertyField’s ‘includeChildren’ flag, like so:

EditorGUILayout.PropertyField(spMyList, true);

If you don’t do this, all you’ll get is the list’s name (sometimes with a foldout) - you won’t get the elements drawn.

Now for FindProperty to work, like I mentioned you have to perform it on a SerializedObject - Now when you create an Editor you’ll get a serializedObject property for your target object so you don’t need to create a new SerializedObject.

But in your case, if you want FindProperty to pick up your nested lists, you need to create a SerializedObject for each CustomObj - With your current setup, it won’t work because the constructor for SerializedObject expects a UnityEngine.Object and not a System.Object

One way around this is to make your CustomObj either a MonoBehaviour or a ScriptableObject. In both cases you have to save the script live somewhere, in case of a MB you could attach it to an empty GO or a prefab that you keep just for this kind of stuff (See Bunny’s hack in the comments here). In case of a ScriptableObject, you need to create an asset for it.

To create a SerializedObject for a UnityEngine.Object, you do:

var so = new SerializedObject(targetObj);

If you don’t like all this, you can forget about SerializedProperties and draw the lists manually. You can always implement Undo on your own. Either via Unity’s Undo, or DEVBUS.


EDIT: It seems that PropertyField is more than enough, here’s a working solution (at least in my Unity 4.5.2)

TestBehaviour.cs

using UnityEngine;

public class TestBehaviour : MonoBehaviour
{
	public TestObject[] array;
}

TestObject.cs

using System;

[Serializable]
public class TestObject
{
	public Transform[] nestedArray;
}

TestEditor.cs

using UnityEditor;

[CustomEditor(typeof(TestBehaviour))]
public class TestEditor : Editor
{
	public override void OnInspectorGUI()
	{
		EditorGUILayout.PropertyField(serializedObject.FindProperty("array"), true);
	}
}