How do I get reorderable ListView's Handle Element in code?

I’m creating a custom inspector which loads and clone’s it’s markup from a .uxml file.
I’m building the .uxml file using the UI Builder, and so far there’s only a ListView with the binding path set to a field on the inspected object which is a list.

At the moment this works and displays all items within the list on the inspected object.
However, I’m trying to make the reorderable items look a little nicer, and ultimately I need to alter the z-index of the #unity-list-view__reorderable-handle so that it’s brought to the front.

Since USS doesn’t have support for z-index, I’d like to try target the #unity-list-view__reorderable-handle and call BringToFront() on it.

I can’t seem to find it with any queries, so how do I target the #unity-list-view__reorderable-handle?
Thank you!

Hi!
The reorderable handles should already be displayed on top of the other elements when dragging. Can you provide more details or screenshots of what you are trying to achieve?
Thanks!

This issue has nothing to do with behavior when dragging.
The reorderable handles are the first child element in any reorderable item parent. Which means the content of each reorderable item is rendered on top of it’s respective handle element.

I want to move the handle to the far right, make the background transparent, so that when the reorderable item’s content is hovered or checked, the entire bar changes color.

By targeting either the reorderable item’s content, or the handle, and calling SendToBack() or BringToFront() respectively, I can achieve the effect I’m looking for.

Here’s an image of the current hover behavior:

Here’s an image of the desired hover behavior:

Perhaps there’s a way to add the reorderable item’s parent element or handle element to a collection in the bindItem callback, then iterate over the collection and call either SendToBack() or BringToFront()?

I tried doing that but I don’t really understand how that callback works and whilst I could send them to the back or front I lost the ability to display the actual item in the inspector. Here’s my broken code:

// in CreateInspectorGUI
listView.bindItem += SendParentToBack;

// outside of CreateInspectorGUI
void SendParentToBack(VisualElement ele, int i)
{
    ele.parent.SendToBack();
}

In the case of the ListView, the children of the #unity-list-view__reorderable-item are displayed using flex-direction: row; in relative position mode, which means that by default, the handle and the content are rendered side-by-side and neither should be rendered on top of the other.

If you want to override the look and feel of the ListView, it is preferable to do this through styling instead of changing the hierarchy (which ultimately is what BringToFront and SendToBack will do), as internal code to the ListView could assume that the first child is the handle.

If you want to put the handle on the right side, you can use:

.unity-list-view__reorderable-item{
    flex-direction: row-reverse;
}

Note that this would change the order for every ListView, so you probably want to restrict it a little bit more.
For changing the handle’s background color, you can use:

.unity-list-view__reorderable-handle{
    background-color: transparent;
}

Hope this helps!

Incorrect, by default the content is rendered after the handle so the content will always be on top if I position the handle and the content to overlap.

I’ve already solved that issue as indicated in the image titled “current hover behaviour”.

I’ll change the handle’s background color to blue and make it’s margin-left -25 to prove that it’s being rendered behind. See screenshot:

Which brings me all the way back to my original question:
How do I get the reorderable item’s handle in code?

(PS: All of this could be fixed with z-index, please implement it!)

Indeed, if you do position the handle and the content to overlap, they will overlap and the content would be rendered on top. I would hardly call that “by default” anymore.

With the styling I provided and adjusting the color of the row (normal and alternate and hover) to match the color of the item, I was able to get something matching what seemed to be your desired hover behaviour without needing to write code. If that was enough, it would be preferable than writing code to achieve the same thing. It seems it’s not enough for your use-case, my apologies.

Documentation says that if bindItem and makeItem are not set, Unity will try to bind to a SerializedProperty if bound, or simply set text in the created Label.

Given the snippet you provided:

// in CreateInspectorGUI
listView.bindItem += SendParentToBack;
// outside of CreateInspectorGUI
void SendParentToBack(VisualElement ele, int i)
{
    ele.parent.SendToBack();
}

What happens here is that you set a binding behaviour, so the default inspector implementation assumes that you are taking charge and will not add a default one. So, essentially, your implementation is missing the actual binding code. Assuming that the element ele is a PropertyField in your snippet, you could do something like:

var property = serializedObject.FindProperty("yourPropertyPathHere").GetArrayElementAtIndex(i);
(ele as PropertyField).BindProperty(property);

Note that depending on the Unity version you are using, you might need to also implement the makeItem callback for it to work. The default implementation returns a new PropertyField. The documentation for the makeItem is located here.

Now to answer your original question. If you take a look at the hierarchy that is created for a list view item, you will get:

#unity-list-view__reorderable-item
    #unity-list-view__reorderable-handle
    #unity-list-view__reorderable-item__container
        #Your element is here

So, to get the reorderable item’s handle in code, you would need to do the equivalent of:

var handle = ele.parent.parent.Q(className:"unity-list-view__reorderable-handle);

This generated hierarchy for a list row is subject to change in the future, so you may want to look for a parent with the .unity-list-view__reorderable-item class on it instead of simply doing parent.parent

Now, I would not advise you to do this, because it’s like turning right three times instead of turning left. With makeItem and bindItem properly implemented, ele.parent.SendToBack(); should be enough (and again here, the generated hierarchy is subject to change in the future).

Cheers!

Yep, pasting that in SendParentToBack() fixes my broken code from my first response, and allows me to achieve my desired result. Thank you!

Oh boy, good to know, I didn’t see explicitly anywhere that the generated content within a ListView is subject to change over time. Might be wise to drop a note in the docs?
Not sure what I can do about that. I guess I’ll look out for everything breaking and then try and figure out what changed?

Overall UI Toolkit is a huge step in the right direction, and I hope that over time the number of CSS properties it supports grows, particularly to include things like Z-Index which from what I can see has been requested for quite some time.

Hopefully Z-Index is implemented before the generated hierarchy is changed :slight_smile:
Thank you for your help!

It’s true for pretty much any generated hierarchy that we have. Adding a new feature sometimes forces us to modify it. The ListView is actually a good example, because the handles are not even generated if the reorder mode is set to simple.

So in your example, it would probably be safer long term to look for a parent with the .unity-list-view__reorderable-item__container instead of parent. We try to keep the same class names as much as we can.