Search Unity

Question Nested Lists in UI Toolkit at runtime

Discussion in 'UI Toolkit' started by fherbst, Apr 8, 2021.

  1. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    I'm trying to wrap my head around UI Toolkit, and wanted to create something that in the past was very easy with any UI system in Unity: a nested list of items, similar to a directory structure.

    I started by creating two UIDocuments;
    a "PsdFile" "group" which simply contains a scroll view
    upload_2021-4-9_0-17-38.png

    and a "LayerGroup" "element" that is supposed to go into that scroll view
    upload_2021-4-9_0-18-28.png

    This in itself has a "Foldout" where more of those "LayerGroup" elements are supposed to go, but for now I would already be happy with a simple flat list.

    Next up, I read that UIDocuments can be parented to each other in the Hierarchy, so I tried that, but according to the docs childs only get attached to the parent's root element. My intuition would have been that they get attached to the #unity-content "slots" of their parents, and that I can somehow choose where they go (this would be similar to how slots work in modern HTML).
    upload_2021-4-9_0-23-0.png
    Expectation would have been the "LayerGroup" objects in between "Label" and "End of file".

    Next up, I tried to instantiate the list items and attach them at runtime.
    The docs refer to template.CloneTree(target) and this returning an item, however the runtime version of CloneTree returns void.
    After digging through reflection via Rider, I found notes about "CloneTree" being obsolete, use VisualElement.Instantiate" which enabled me to actually instantiate childs after querying the right attachment points with Q<>.

    This allowed me to get kind of the hierarchical structure I was after:
    upload_2021-4-9_0-44-16.png

    So far the result is similar to what I would have had with UGUI, minus
    - the ability to preview in the editor how the nesting structure looks like
    - the ability to see attached items at runtime in the hierarchy

    In addition, the whole process took me 10x longer, and I ended up with a number of UIDocument and StyleSheet assets plus needed to write code that feels hacky.

    I also tried to get binding to work but not sure if that is supposed to work at runtime yet, and how I would provide those "attachment points" for bindings. If I understand the intention of UI Toolkit right, the goal here would be to just point a hierarchical serialized object at that top-level UIDocument and, voila, have some magic bindings just create that hierarchy for me, abstracting away the need to even think about the hierarchy (as the data would just be turned into nice UI).

    Is this workflow incorrect? Am I missing something?

    Thanks,
    Felix
     
  2. LogicFlow

    LogicFlow

    Joined:
    Aug 18, 2018
    Posts:
    33
    Implementation of an expandable / tree list in UI Toolkit is trivial, nothing complex here.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UIElements;
    3.  
    4. public class TestUIToolkit : MonoBehaviour
    5. {
    6.     //inspector-set members:
    7.     [SerializeField] VisualTreeAsset myItemAsset; //.uxml template file from UI Toolkit Builder
    8.     [SerializeField] UIDocument doc; //document created in scene.
    9.  
    10.     private void OnEnable()
    11.     {
    12.         var panel = doc.rootVisualElement.Q<VisualElement>("PanelMain");
    13.  
    14.         var foldOut0 = new Foldout();
    15.         var foldOut1 = new Foldout();
    16.  
    17.         //create the foundation by adding the root foldout to the panel.
    18.         panel.contentContainer.Add(foldOut0);
    19.  
    20.         //create further structure.
    21.         foldOut0.Add(myItemAsset.Instantiate()); //add leaf to root foldOut0, before sub-foldOut1.
    22.         foldOut0.Add(foldOut1);
    23.  
    24.         foldOut0.Add(myItemAsset.Instantiate()); //add leaf to root foldOut0, after sub-foldOut1.
    25.         foldOut1.Add(myItemAsset.Instantiate()); //add leaf to foldOut1.
    26.  
    27.         //1. Set up same by looping over existing data collections, as you like.
    28.         //2. Instead of .Instantiate()ing a template, you can use new Slider(), new Toggle(), etc.
    29.     }
    30. }
     
    Last edited: May 22, 2022