Search Unity

Support editing multiple objects with ReorderableList in custom inspector.

Discussion in 'Immediate Mode GUI (IMGUI)' started by keenanwoodall, Nov 1, 2018.

  1. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    I'm trying to use a reorderable list, but I'm having a hard time implementing it in a way that allows multiple objects to be selected. Has anyone managed to create a reorderable list that works well on all targets?
     
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,281
    ReorderableList does not have support for multiple selection. I would suggest you don't use ReorderableList and instead use TreeView
     
    Dr-Nick and keenanwoodall like this.
  3. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    This is very cool, thanks for pointing me to it!
     
    karl_jones likes this.
  4. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Been a bit, but if anyone wants to better support reorderable lists with multiple selections you can do it pretty easily by not using the SerializedProperty/Object API. Full, perfect support of every multi-edit scenario is probably not achievable, but it's not hard to support adding/removing elements without losing unique values.

    Add an AddDefault() and RemoveAt() function to whatever class the list is displaying (and actually implement them haha. AddDefault should add a default element to the end of your collection and RemoveAt should remove an element at an index).
    Then when you initialize your list callbacks, setup the onAdd and onRemove like so (replacing my Palette class with yours, and ignore that the RemoveAt function is a generic TryRemoveAt function in my use-case, just need to do that cuz I'm doing weird stuff)
    Code (CSharp):
    1. list.onAddCallback = list =>
    2. {
    3.     Undo.RecordObjects(targets, "Add Palette Element");
    4.     foreach (var t in targets)
    5.     {
    6.         if (t is Palette palette)
    7.         {
    8.             palette.AddDefault();
    9.         }
    10.     }
    11.     serializedObject.SetIsDifferentCacheDirty();
    12.     serializedObject.Update();
    13. };
    14. list.onRemoveCallback = list =>
    15. {
    16.     if (list.index > -1 && list.index < list.count) // idk if this check is necessary
    17.     {
    18.         Undo.RecordObjects(targets, "Remove Palette Element");
    19.         foreach (var t in targets)
    20.         {
    21.             if (t is Palette palette)
    22.             {
    23.                 palette.TryRemoveAt<Swatch>(list.index);
    24.             }
    25.         }
    26.  
    27.         serializedObject.SetIsDifferentCacheDirty();
    28.         serializedObject.Update();
    29.     }
    30. };
    The important part is the last two lines of each callback.
    Code (CSharp):
    1. serializedObject.SetIsDifferentCacheDirty();
    2. serializedObject.Update();
    The previous lines modify the list in memory, but not their serialized object representation. Calling SetIsDifferentCacheDirty() and Update() forces the serializedObject to update it's representation of the data after the foreach loop changed it. Haven't tried it yet, but I imagine adding support for reordering shouldn't be much harder to add.
     
    Last edited: May 19, 2021
    hamza_unity995 likes this.