ListView takes Focus even though it is not Focusable

Sometimes ListView takes arrow input (and moves up/down the list) even though it is not Focusable. When it is Focusable but not currently in focus the same happens.

Otherwise it works really well and is pretty easy to work with.

ListView is Focusable by default, but even if you make it not focusable after creation, its internal contentContainer, which actually handles the arrow keys, is still focusable. That may be your issue.

That solved it, thanks.

listView.Q("unity-content-container").focusable = false;

Though the container, when still focusable, seems to still take input when it shouldn’t be in focus. E.g. I’ve clicked somewhere else on the screen. Similarly I have a text field that takes input keys at all times.

It’s possible clicking somewhere that ignores mouse events (has pickingMode set to none) will leave the focus where it is currently. Does the ListView still eat events if you focus a TextField that is outside the ListView?

I tried to test, but at the moment my ListView doesn’t respond to any key input (both ListView and container are focusable). However I tried the reverse. After selecting something from the ListView the TextField still takes input.

Hope it helps

Ok, that’s odd. I thought the original problem above was that ListView responded to too many key events. Are you saying now it responds to none?

Yes and yes. Honestly it’s really hard to test this because it seems random how it works each time I try.

Part of the fault may be in UI Builder when I unset Focusable it looks like its unset state is off. But saving and reopening UI Builder it has changed to on.

But I’m gonna stop testing this, because the behaviour seems random each time.

Keep in mind that UI Builder will not remember the state of any controls you add to your document between domain reloads, undo/redo, window layout changes, and Builder/Unity restarts. When you turn on Preview mode in the UI Builder and start interacting with elements, all of that state is temporary.

I don’t understand. I’m not using Preview, so that shouldn’t be the problem. I’m just changing properties (like Focusable) on elements in UI Builder and during runtime with C#.

When not in the Builder’s Preview mode, no element in your UI document can receive mouse events and therefore focus. Changing the “Focusable” attribute shouldn’t do anything if you’re not (or cannot be) interacting with the element. Hence my clarification questions.

There are sometimes issues with attributes on elements not being remembered in the UI Builder because the Builder relies on reflecting C# fields with similar names to get their values and sometimes they are not found. But I just tried Focusable and that one seems to work ok.

When you say “during runtime with C#”, is this via a custom C# VisualElement (that operates inside the UI Builder’s canvas) or in some host EditorWindow/UIDocument/Editor (ie. not running inside the UI Builder)?

I think we might be misunderstanding each other. All my testing is during runtime. All UI is runtime UI (not Editor UI).

“When you say “during runtime with C#”, is this via a custom C# VisualElement (that operates inside the UI Builder’s canvas) or in some host EditorWindow/UIDocument/Editor (ie. not running inside the UI Builder)?”

I think the former? In my scene I have an Event System and a UI Document. From the UI Document’s Source Asset I search for each element I want to change (filling a ListView etc.). That is done from a C# script.

Got it. Let’s leave it at:

:slight_smile:

We’ll keep an eye on these focus issues.

1 Like

In Unity 2021.2.7f1 when ListView used (programmatically or through UI Builder, does not matter) with “Show Foldout Header” options setted to true, list content will duplicated after fold/unfold.

Before fold:

After fold-unfold:

And here is inspector code:

[CustomEditor(typeof(Path))]
    public class PathInspector : Editor
    {
        [SerializeField]
        private VisualTreeAsset _pathInspectorUXML;

        public override VisualElement CreateInspectorGUI()
        {
            var inspector = new VisualElement();
            _pathInspectorUXML.CloneTree(inspector);

            var points = ((Path)serializedObject.targetObject).GetComponentsInChildren<Transform>().Skip(1).ToList();

            var pointsList = inspector.Q<ListView>("Points");
           
            pointsList.itemsSource = points;
            pointsList.makeItem = () => new GroupBox();
            pointsList.bindItem = (gr, index) =>
            {
                var group = (GroupBox)gr;
                group.style.flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row);
                group.style.borderLeftWidth = 10f;
                group.style.justifyContent = new StyleEnum<Justify>(Justify.SpaceAround);

                var label = new Label { text = points[index].name };
                label.style.width = 60f;
                label.style.unityTextAlign = new StyleEnum<TextAnchor>(TextAnchor.MiddleLeft);

                var objref = new ObjectField() { value = points[index], objectType = typeof(GameObject) };
                objref.style.width = 150f;

                var position = new Vector3Field() { value = points[index].position };
                position.Q("unity-x-input").ElementAt(1).style.width = 100f;

                group.Add(label);
                group.Add(objref);
                group.Add(position);

                //((Label)group.ElementAt(1)).style.unityTextAlign = new StyleEnum<TextAnchor>(TextAnchor.MiddleLeft);
            };

            return inspector;
        }
    }

Solved…