Search Unity

Custom editor: display array within ReorderableList

Discussion in 'Scripting' started by Xarbrough, Apr 26, 2015.

  1. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I have a CustomEditor that displays my level builder information. It uses the UnityEditorInternal.ReorderableList to draw a list of levels with their properties in the Inspector.

    Code (CSharp):
    1. private void OnEnable()
    2. {
    3.     //Get top-level list property
    4.     list = new ReorderableList(serializedObject,
    5.                                 serializedObject.FindProperty("levels"),
    6.                                 true, true, true, true);
    7.      
    8.     GUIStyle rightAlign = new GUIStyle();
    9.     rightAlign.alignment = TextAnchor.UpperRight;
    10.  
    11.     //Draw and style list elements
    12.     list.drawElementCallback =
    13.     (Rect rect, int index, bool isActive, bool isFocused) => {
    14.         var element = list.serializedProperty.GetArrayElementAtIndex(index);
    15.         rect.y += 2;
    16.  
    17.         var third = rect.width / 3f;
    18.  
    19.         EditorGUI.LabelField(
    20.             new Rect(rect.x, rect.y, 18f, EditorGUIUtility.singleLineHeight),
    21.             element.FindPropertyRelative("id").intValue.ToString(), rightAlign);
    22.  
    23.         EditorGUI.PropertyField(
    24.             new Rect(rect.x + 25f, rect.y, third - 30f, EditorGUIUtility.singleLineHeight),
    25.             element.FindPropertyRelative("name"), GUIContent.none);
    26.     }
    27. }
    So far everything works fine, but now I would like to add a property for an array within my reorderable list. When I try to use element.FindPropertyRelative like in the example above, the inspector draws an empty drop down arrow.

    How can I draw array elements like the default Inspector does within my ReorderableList? If possible, I would like to stick to UnityEditorInternal.ReorderableList because it already has all the neat callbacks and most of what I need my custom Inspector to do.

    Thanks for any suggestions!
     
    Last edited: Dec 3, 2020
  2. nratcliff

    nratcliff

    Joined:
    Jul 5, 2014
    Posts:
    66
    Reviving this thread half a decade later. Did you ever figure this out? I can't get any foldout (like an array) in a ReorderableList to not draw as a blank area when expanded.

     
  3. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I probably did not back then, but future-me to the rescue, here is a working example:

    upload_2020-1-8_22-7-19.png


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEditor;
    3. using UnityEditorInternal;
    4. using UnityEngine;
    5.  
    6. public class Test : MonoBehaviour
    7. {
    8.     public List<LevelData> levels;
    9.  
    10.     [System.Serializable]
    11.     public class LevelData
    12.     {
    13.         public string[] names;
    14.     }
    15. }
    16.  
    17. [CustomEditor(typeof(Test))]
    18. public class TestEditor : Editor
    19. {
    20.     private ReorderableList list;
    21.  
    22.     private void OnEnable()
    23.     {
    24.         list = new ReorderableList(
    25.             serializedObject,
    26.             serializedObject.FindProperty("levels"),
    27.             true, true, true, true)
    28.         {
    29.             elementHeightCallback = ElementHeightCallback,
    30.             drawElementCallback = DrawListElement
    31.         };
    32.     }
    33.  
    34.     private float ElementHeightCallback(int index)
    35.     {
    36.         // Set the height of each row dynamically depending on the height of the names entries.
    37.         SerializedProperty namesProp = GetNamesProp(index);
    38.         return EditorGUI.GetPropertyHeight(namesProp) + EditorGUIUtility.standardVerticalSpacing;
    39.     }
    40.  
    41.     private void DrawListElement(Rect rect, int index, bool isActive, bool isFocused)
    42.     {
    43.         SerializedProperty namesProp = GetNamesProp(index);
    44.  
    45.         // By default, the array dropdown is offset to the left which intersects with
    46.         // the drag handle, so we can either indent the array property or inset the rect.
    47.         EditorGUI.indentLevel++;
    48.  
    49.         // Take note of the last argument, since this is an array,
    50.         // we want to draw it with all of its children.
    51.         EditorGUI.PropertyField(rect, namesProp, includeChildren: true);
    52.         EditorGUI.indentLevel--;
    53.     }
    54.  
    55.     private SerializedProperty GetNamesProp(int index)
    56.     {
    57.         var element = list.serializedProperty.GetArrayElementAtIndex(index);
    58.         return element.FindPropertyRelative("names");
    59.     }
    60.  
    61.     public override void OnInspectorGUI()
    62.     {
    63.         serializedObject.Update();
    64.         list.DoLayoutList();
    65.         serializedObject.ApplyModifiedProperties();
    66.     }
    67. }
    68.