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

ListView with runtime visual element?

Discussion in 'UI Toolkit' started by sohoperry, Mar 23, 2021.

  1. sohoperry

    sohoperry

    Joined:
    Nov 29, 2016
    Posts:
    4
    Hi,

    I'm trying to dynamically populate a list at runtime using ListView but nothing appears and MakeItem/BindItem aren't being called. I'm creating/populating it in the constructor of a custom VisualElement and adding that to a .uxml file with a label above it.

    Code (CSharp):
    1. public class RoomList : VisualElement
    2. {
    3.     public new class UxmlFactory : UxmlFactory<RoomList, UxmlTraits> { }
    4.     public new class UxmlTraits : VisualElement.UxmlTraits { }
    5.  
    6.     private ListView listView;
    7.  
    8.     public RoomList()
    9.     {
    10.         IList items = Resources.LoadAll<RoomAsset>("Rooms");
    11.         listView = new ListView(items, 20, MakeItem, BindItem)
    12.         {
    13.             selectionType = SelectionType.Single,
    14.             horizontalScrollingEnabled = true
    15.         };
    16.         listView.style.flexGrow = 1f;
    17.         listView.style.flexShrink = 0f;
    18.         listView.style.flexBasis = 0f;
    19.         listView.onSelectionChange += Debug.Log;
    20.         Add(listView);
    21.         Debug.Log("RoomList constructor" + items.Count);
    22.     }
    23.  
    24.     private void BindItem(VisualElement element, int index)
    25.     {
    26.         Debug.Log("RoomList BindItem");
    27.         var item = listView.itemsSource[index];
    28.         (element as TextElement).text = (item as RoomAsset).Name;
    29.     }
    30.  
    31.     private VisualElement MakeItem()
    32.     {
    33.         Debug.Log("RoomList MakeItem");
    34.         //return new Label();
    35.         var ele = new TextElement();
    36.         ele.style.unityTextAlign = TextAnchor.MiddleLeft;
    37.         ele.style.paddingLeft = 5;
    38.         ele.style.flexGrow = 1f;
    39.         ele.style.flexShrink = 0f;
    40.         ele.style.flexBasis = 0f;
    41.         return ele;
    42.     }
    43. }
    44.  
    Code (CSharp):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    2.     <Style src="Room.uss" />
    3.     <ui:Label text="Rooms" display-tooltip-when-elided="true" style="font-size: 24px;" />
    4.     <RoomList name="RoomList" style="flex-direction: column;" />
    5. </ui:UXML>
    6.  
    If put this in an editor window it does work:

    Code (CSharp):
    1. void OnEnable()
    2.     {
    3.         IList items = Resources.LoadAll<RoomAsset>("Rooms");
    4.         listView = new ListView(items, 20, MakeItem, BindItem)
    5.         {
    6.             selectionType = SelectionType.Single,
    7.             horizontalScrollingEnabled = true
    8.         };
    9.         listView.style.flexGrow = 1f;
    10.         listView.style.flexShrink = 0f;
    11.         listView.style.flexBasis = 0f;
    12.         listView.onSelectionChange += Debug.Log;
    13.         rootVisualElement.Add(listView);
    14.     }
    Is not possible to use this at runtime? Is there an alternative?

    Cheers

    Versions:
    Unity 2021.1.0b12.2144.20
    UI Toolkit 1.0.0-preview.14
    UI Builder 1.0.0-preview.13
     
  2. griendeau_unity

    griendeau_unity

    Unity Technologies

    Joined:
    Aug 25, 2020
    Posts:
    230
    Hi!

    I think you're doing everything right here. I'm pretty sure the only thing missing is that your RoomList element does not grow. So right now it is probably there, but you can't see it. A good way to check that is to use the UI Debugger (Window -> UI Toolkit -> Debugger) and pick the game panel. RoomList's height is probably 0, so you would have to change its flexGrow/flexShrink attributes or set a minHeight, depending on your needs.

    Cheers!
     
    BackgroundMover likes this.
  3. sohoperry

    sohoperry

    Joined:
    Nov 29, 2016
    Posts:
    4
    Ah thank you, that does seem to work.
    I'd like to load another element defined a .uxml file instead of just a label and bind some data to it.
    Is there any code samples for that? I've only seen uxml files loaded in code via AssetDatabase which is editor only I believe.

    Thanks
     
  4. griendeau_unity

    griendeau_unity

    Unity Technologies

    Joined:
    Aug 25, 2020
    Posts:
    230
    Yes, AssetDatabase is editor only. The runtime equivalent would be to load from asset bundles, or from the Resources folder with Resources.Load<VisualTreeAsset>("path-to-your-asset"). You could also serialize your VisualTreeAsset in a script directly (public variable or a private variable with the [SerializeField] attribute).

    There are a few sample, but not exactly for what you want to do. In Package Manager, click on the UI Toolkit package and import samples under the Samples foldout. You can see in there the last option I mentioned, i.e. passing the visual tree asset in scripts. It's assigned to a UI Document in the examples, but in your case you would call the CloneTree method instead.
     
  5. sohoperry

    sohoperry

    Joined:
    Nov 29, 2016
    Posts:
    4
    Lovely, thanks for the info.
     
  6. Malavia

    Malavia

    Joined:
    Aug 28, 2019
    Posts:
    10
    I don't see UI Toolkit package in Package Manager, only UI Builder.
     
  7. sohoperry

    sohoperry

    Joined:
    Nov 29, 2016
    Posts:
    4
    Think it depends on version / whether you have experimental packages enabled in project settings.

    You can add "com.unity.ui": "1.0.0-preview.14" to your manifest.json.