Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

What is the best way to do a reorderable list?

Discussion in 'Editor & General Support' started by laurentlavigne, Jan 3, 2018.

  1. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,994
    Yes, what's the easiest to use, that don't require to change data type and works out of the box with nesting (and bonus ... with simple-ish code).

    So far I found this https://forum.unity.com/threads/reorderable-list-v2.339717/ which gives fabulous looking reordarable lists where each element can also collapse BUT requires the arrays to be ReorderableArrays

    and this one which is generic, automatic, and just great BUT with code I don't understand like this beast
    Code (CSharp):
    1.         bool isdefaultScriptProperty = property.name.Equals("m_Script") && property.type.Equals("PPtr<MonoScript>") && property.propertyType == SerializedPropertyType.ObjectReference && property.propertyPath.Equals("m_Script");
    2.  
    and some glitches here and there with the display like that


    https://medium.com/developers-writi...-and-lists-in-unity3d-by-default-e4fba13d1b50

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditorInternal;
    4. using System.Collections.Generic;
    5.  
    6. [CustomEditor(typeof(UnityEngine.Object), true, isFallback = true)]
    7. [CanEditMultipleObjects]
    8. public class CustomEditorBase : Editor
    9. {
    10.     private Dictionary<string, ReorderableListProperty> reorderableLists;
    11.  
    12.     protected virtual void OnEnable()
    13.     {
    14.         this.reorderableLists = new Dictionary<string, ReorderableListProperty>(10);
    15.     }
    16.  
    17.     ~CustomEditorBase()
    18.     {
    19.         this.reorderableLists.Clear();
    20.         this.reorderableLists = null;
    21.     }
    22.  
    23.     public override void OnInspectorGUI()
    24.     {
    25.         EditorGUILayout.LabelField("Custom Editor", EditorStyles.centeredGreyMiniLabel);
    26.         Color cachedGuiColor = GUI.color;
    27.         serializedObject.Update();
    28.         var property = serializedObject.GetIterator();
    29.         var next = property.NextVisible(true);
    30.         if (next)
    31.             do
    32.             {
    33.                 GUI.color = cachedGuiColor;
    34.                 this.HandleProperty(property);
    35.             } while (property.NextVisible(false));
    36.         serializedObject.ApplyModifiedProperties();
    37.     }
    38.  
    39.     protected void HandleProperty(SerializedProperty property)
    40.     {
    41.         //Debug.LogFormat("name: {0}, displayName: {1}, type: {2}, propertyType: {3}, path: {4}", property.name, property.displayName, property.type, property.propertyType, property.propertyPath);
    42.         bool isdefaultScriptProperty = property.name.Equals("m_Script") && property.type.Equals("PPtr<MonoScript>") && property.propertyType == SerializedPropertyType.ObjectReference && property.propertyPath.Equals("m_Script");
    43.         bool cachedGUIEnabled = GUI.enabled;
    44.         if (isdefaultScriptProperty)
    45.             GUI.enabled = false;
    46.         //var attr = this.GetPropertyAttributes(property);
    47.         if (property.isArray && property.propertyType != SerializedPropertyType.String)
    48.             this.HandleArray(property);
    49.         else
    50.             EditorGUILayout.PropertyField(property, property.isExpanded);
    51.         if (isdefaultScriptProperty)
    52.             GUI.enabled = cachedGUIEnabled;
    53.     }
    54.  
    55.     protected void HandleArray(SerializedProperty property)
    56.     {
    57.         var listData = this.GetReorderableList(property);
    58. //        if (!property.isExpanded)
    59. //        {
    60. //            EditorGUILayout.BeginHorizontal(EditorStyles.foldout);
    61. //            property.isExpanded = EditorGUILayout.ToggleLeft(string.Format("{0}[]", property.displayName), property.isExpanded, EditorStyles.boldLabel);
    62. //            EditorGUILayout.LabelField(string.Format("size: {0}", property.arraySize));
    63. //            EditorGUILayout.EndHorizontal();
    64. //        }
    65. //        else {
    66.             listData.List.DoLayoutList();
    67. //        }
    68.     }
    69.  
    70.     protected object[] GetPropertyAttributes(SerializedProperty property)
    71.     {
    72.         return this.GetPropertyAttributes<PropertyAttribute>(property);
    73.     }
    74.  
    75.     protected object[] GetPropertyAttributes<T>(SerializedProperty property) where T : System.Attribute
    76.     {
    77.         System.Reflection.BindingFlags bindingFlags = System.Reflection.BindingFlags.GetField
    78.             | System.Reflection.BindingFlags.GetProperty
    79.             | System.Reflection.BindingFlags.IgnoreCase
    80.             | System.Reflection.BindingFlags.Instance
    81.             | System.Reflection.BindingFlags.NonPublic
    82.             | System.Reflection.BindingFlags.Public;
    83.         if (property.serializedObject.targetObject == null)
    84.             return null;
    85.         var targetType = property.serializedObject.targetObject.GetType();
    86.         var field = targetType.GetField(property.name, bindingFlags);
    87.         if (field != null)
    88.             return field.GetCustomAttributes(typeof(T), true);
    89.         return null;
    90.     }
    91.  
    92.     private ReorderableListProperty GetReorderableList(SerializedProperty property)
    93.     {
    94.         ReorderableListProperty ret = null;
    95.         if (this.reorderableLists.TryGetValue(property.name, out ret))
    96.         {
    97.             ret.Property = property;
    98.             return ret;
    99.         }
    100.         ret = new ReorderableListProperty(property);
    101.         this.reorderableLists.Add(property.name, ret);
    102.         return ret;
    103.     }
    104.  
    105.     #region Inner-class ReorderableListProperty
    106.     private class ReorderableListProperty
    107.     {
    108.         /// <summary>
    109.         /// ref http://va.lent.in/unity-make-your-lists-functional-with-reorderablelist/
    110.         /// </summary>
    111.         public ReorderableList List { get; private set; }
    112.  
    113.         private SerializedProperty _property;
    114.         public SerializedProperty Property
    115.         {
    116.             get { return this._property; }
    117.             set
    118.             {
    119.                 this._property = value;
    120.                 this.List.serializedProperty = this._property;
    121.             }
    122.         }
    123.  
    124.         public ReorderableListProperty(SerializedProperty property)
    125.         {
    126.             this._property = property;
    127.             this.CreateList();
    128.         }
    129.  
    130.         ~ReorderableListProperty()
    131.         {
    132.             this._property = null;
    133.             this.List = null;
    134.         }
    135.  
    136.         private void CreateList()
    137.         {
    138.             bool dragable = true, header = true, add = true, remove = true;
    139.             this.List = new ReorderableList(this.Property.serializedObject, this.Property, dragable, header, add, remove);
    140.             this.List.drawHeaderCallback += rect => EditorGUI.LabelField (rect, this._property.displayName);// EditorGUI.ToggleLeft(rect, this._property.displayName, this._property.isExpanded, EditorStyles.boldLabel);
    141.             this.List.onCanRemoveCallback += (list) => { return this.List.count > 0; };
    142.             this.List.drawElementCallback += this.drawElement;
    143.             this.List.elementHeightCallback += (idx) => { return Mathf.Max(EditorGUIUtility.singleLineHeight, EditorGUI.GetPropertyHeight(this._property.GetArrayElementAtIndex(idx), GUIContent.none, true)) + 4.0f; };
    144.         }
    145.  
    146.         private void drawElement(Rect rect, int index, bool active, bool focused)
    147.         {
    148.             if (this._property.GetArrayElementAtIndex(index).propertyType == SerializedPropertyType.Generic)
    149.             {
    150.                 EditorGUI.LabelField(rect, this._property.GetArrayElementAtIndex(index).displayName);
    151.             }
    152.             //rect.height = 16;
    153.             rect.height = EditorGUI.GetPropertyHeight(this._property.GetArrayElementAtIndex(index), GUIContent.none, true);
    154.             rect.y += 1;
    155.             EditorGUI.PropertyField(rect, this._property.GetArrayElementAtIndex(index), GUIContent.none, true);
    156.             this.List.elementHeight = rect.height + 4.0f;
    157.         }
    158.     }
    159.     #endregion
    160. }
     
    FlightOfOne likes this.
  2. terresquall

    terresquall

    Joined:
    Mar 2, 2014
    Posts:
    29
    mullenator and Mario-M701 like this.
  3. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,994
    2020.1 has array reordering now, 2 years is all it took.
     
    hippocoder likes this.
  4. LazyBensch

    LazyBensch

    Joined:
    Oct 22, 2014
    Posts:
    1
    wait, @laurentlavigne i'm on 2020.1.0b8 and do not have reorderable arrays. can you point me to the api? i can't find it.
     
  5. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,994
    @LazyBensch I thought it did, but nope, that was all a dream~~~~~~
     
    koirat likes this.
  6. muhammad_ali_safdar

    muhammad_ali_safdar

    Joined:
    Jan 7, 2015
    Posts:
    15