Search Unity

ListView - change selection from script & SHIFT multiselect

Discussion in 'UI Toolkit' started by XGT08, Sep 2, 2019.

  1. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Hello,

    I am implementing a listview in which the user can create and delete elements. The list view uses the Multiselect selection type. I would also like to allow the user to Undo/Redo add/remove operations from the list. The problem is that when I delete the selected items (which I need to keep track of manually via the onSelectionChanged callback), the list doesn't change its selection information even though I am calling Refresh() so the selected indices are mapped to whatever remains in the list.

    I tried setting the selected index to -1. It works, however, now if I Undo the operation, the selection disappears. I can bring the items back in the list, but I can not reselect the items.

    So here are a few suggestions for the list view:
    1. the possibility to retrieve ALL selected indices. If there is such thing as Multiselect selection type, it stands to reason that there should be a way to retrieve all selected indices. Not just the first index.
    2. the possibility to change the selected indices manually. Useful for the handling of Undo/Redo situations such as the one described above. Might be useful in other scenarios too.
    3. it would be nice to have SHIFT + ARROW multi select. For example, in the hierarchy view, if I hold down SHIFT and then press UP/DOWN, the selection grows or shrinks. The ListView class only supports SHIFT in conjunction with the mouse. UP/DOWN are not currently supported. Not super important, but it would definitely be nice to have.

    4 (SUPER NICE TO HAVE :D ). a list view class with elements arranged in a grid-like manner. In my case I need this to render a list of prefab previews. The previews must be treated as list items which can be selected, deleted etc. For the moment, it seems I will have to implement this functionality myself. Not a biggie, but it would help a lot to have a list view with a grid layout.

    Thanks,
    Andrew
     
  2. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    ListView has an internal callback named
    getItemId
    which lets you customize how the ids for your items are generated. The default is just using their index which in your case leads to reselection of the wrong item. You can use this callback to generate a unique id for your items so selection is always on the correct item.

    Unfortunately (and this will change in the future), this property is marked internal in the current version. My suggestion is to copy the current implementation from:
    https://github.com/Unity-Technologies/UnityCsReference/blob/master/Modules/UIElements/ListView.cs
    and mark this property public.
     
  3. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Hi uDamian,

    Thanks for the response. Are there any plans to allow us to retrieve all selected items (regardless of the way in which the item id is mapped)? Also is there a way to serialize the selection between script reloads?

    EDIT: I will definitely check the implementation in the link you gave me. That should be very helpful. I'm sure I can mess around with it and change it for my own needs :)
     
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Yep! We are working on our standard controls as we speak, including making TreeView public.
     
    XGT08 likes this.
  5. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Awesome! It's a great API! I love using it, it's just that in its current state there seem to be a few setbacks :D.

    Nevertheless, great job! I can't wait to see it improved!
     
  6. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    @uDamian
    I just have one more question :) Is there any plan to implement a list view that arranges elements in a grid-like manner. This is related to my ScrollView post (which by the way - problem solved!). So instead of having items arranged one below the other, have them sit one after the other on the same row and only move to the next row when there is no more room.

    I am asking this because I might need to implement this list view class myself if this is not/will be available. I just don't want to start working on it if it's already there or if there are plans to implement it.
     
  7. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    We have plans to add a GridView control that works like a spreadsheet and can have a column be a tree (similar to the IMGUI TreeView), however, this would still operate like a ListView in that it will recycle each row, with each row representing one data item.

    If I understand correctly, you're looking for something similar to the Project window in Two-Column Mode with large icons, where they fill each row and then wrap. Is that correct? If so, this is not in our short term plans. It's something that might come in the future but for now, if you don't have a huge number of element I recommend just using ScrollView.

    If you do want to have recycling/virtualization, you might need to implement something yourself. My recommendation is to use ListView and in the bindItem() callback determine the width of your row and add only as many "boxes" as can fit. That is, still take advantage of ListView's row-based virtualization but manually fill each row yourself as the user scrolls.
     
  8. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Thanks Damian,

    What I am trying to accomplish is this:
    PrefabPreviewGrid.png

    I did that with IMGUI.

    I have already started working on a custom ListView class. I still have trouble with the selection mechansim in the current ListView implementation. Plus there are a few things I would need like SHIFT + ARROW select and also be able to select with LEFT and RIGHT arrow keys. :)

    I do have one question though. Do you think it would hurt performance too much if I didn't implement the recycle mechanism? Basically, I am planning to leave all elements there as they are created. For the moment at least, element recycling is not something I am willing to implement :D
     
  9. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Only if you have _a lot_ of elements or they are very expensive to create initially. It's a balancing act. That said, if you don't need the recycling than just use ScrollView with wrapping. No need for anything fancier.
     
    XGT08 likes this.
  10. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Thanks uDamian,

    That's what I did and it works great. I made a list view that supports 2 different types of layouts: Standard and Grid. No recycling. Works like a charm :)

    Thanks!
     
  11. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Hi @uDamian ,

    I just noticed that when a scroll view has the following properties set:
    contentContainer.style.flexDirection = Row;
    contentContainer.style.flexWrap = Wrap;

    the vertical scrollbar disappears. For example:

    PreviewScroll.png

    This is an example of a list view I implemented to support grid layout. All previews are children of a scroll view that uses the above mentioned style. The scroll view uses the Vertcal ScrollViewMode.

    If I set the flex direction to Column, the scroll bar appears. It seems that Row flex direction with wrapping does not support a vertical scrollbar. It would be great if this could be changed :) In this situation I need to scroll the contents of the window to show the prefabs below.

    Thanks,
    Andrew
     
    sergiosoba likes this.
  12. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Hi,
    This is normal since the content container of the ScrollView is set to "flex-direction: row" it will not be able to grow bigger then its parent in the cross-axis (vertically). That is why no scrollbar is shown.
     
  13. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Ok. But is there a way to add a vertical scrollbar to achieve the grid layout effect? If there isn't, this basicly renders the combination of FlexDirection.Row and FlexWrap.Wrap quite limited:) It is very common to have elements arranged in a grid layout that go outside the bounds of the view area.
     
  14. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    229
    Yes there's always a way :)

    In that case I think the easiest way is to add an intermediate container to hold all your elements instead of adding them directly to the ScrollView content container.

    This could look like this :
    Code (CSharp):
    1.  
    2. var scrollView = new ScrollView();
    3. rootVisualElement.Add(scrollView);
    4.  
    5. var gridContainer = new VisualElement();
    6. gridContainer.AddToClassList("grid-container");
    7.            
    8. scrollView.Add(gridContainer);
    9.            
    10. for (int i = 0; i < 10; i++)
    11. {
    12.     var item = new VisualElement();
    13.     item.AddToClassList("grid-item");
    14.                
    15.     gridContainer.Add(item);
    16. }
    And the USS:
    Code (JavaScript):
    1. .grid-container {
    2.     flex-direction: row;
    3.     flex-wrap: wrap;
    4. }
    5.  
    6. .grid-item {
    7.     width: 200px;
    8.     height: 200px;
    9.     border-radius: 4px;
    10.     border-width: 8px;
    11.     border-color: #AFAFAF;
    12.     background-color: #0A0A0A;
    13. }
     
    sergiosoba and XGT08 like this.
  15. XGT08

    XGT08

    Joined:
    Aug 1, 2013
    Posts:
    1,903
    Oh... Works like a charm! I really thought I was going to have to drop what I've done up until this point and use IMGUI instead :D. Thank you very much!
     
    jonathanma_unity likes this.
  16. sergiosoba

    sergiosoba

    Joined:
    Apr 28, 2017
    Posts:
    8
    Thanks jonathanma_unity!
    I solved it like this:

    Code (CSharp):
    1. var scrollView = new ScrollView();
    2. rootVisualElement.Add(scrollView);
    3. var gridContainer = new VisualElement();
    4. gridContainer.style.flexDirection = FlexDirection.Row;
    5. gridContainer.style.flexWrap = Wrap.Wrap;        
    6. scrollView.Add(gridContainer);
    7.          
    8. for (int i = 0; i < 10; i++)
    9. {
    10.     var item = new VisualElement();
    11.     item.style.width = 200;
    12.     item.style.height= 200;
    13.     item.style.backgroundColor = Color.black;            
    14.     gridContainer.Add(item);
    15. }