Shouldn't clicking outside a textfield clear focus? Curious why this isn't standard behaviour for Ma...
c
Shouldn't clicking outside a textfield clear focus? Curious why this isn't standard behaviour for Material components
I suppose it's variable in the sampling of the apps installed on my own phone... Ultimately I guess it's better to have a clear next action, input, etc. for the user to progress towards, which will change the focus anyhow
e
it's default Android behavior: focus should move to something else that can take focus. apps that are clearing focus are doing something special
s
Interestingly enough, I just yesterday happened to stumble upon this
clearFocusOnTap
modifier https://kotlinlang.slack.com/archives/CJLTWPH7S/p1682437025136049?thread_ts=1682337217.318679&cid=CJLTWPH7S and I tried it out in our app and it works perfectly fine. Just need to decide which component will be the one that bears that behavior, for us I slapped it into the background of the screen where I needed this behavior and it simply worked.
c
@Stylianos Gakis thanks for the headsup - I might give that a shot as well! @ephemient I agree that there should always be a next thing that receives focus. However, I've also noticed that in longer input forms, some users like to preview the whole form first, test some input to see what's possible, etc. In that situation, I've seen them taping on the screen to try to clear the keyboard in my app.
j
Came here hoping there was a good answer on this. @Christopher Mederos totally agree. Users know to do that because it's expected and there should be a reasonable way to implement without mods at the root of every screen AND on every button. @ephemient Always having a next is different from responding when the user actively clicks (not scrolls). Clicking implies an intent, and dropping focus on clicks outside the flow isn't special, it's expected.
e
it may be what most users expect but it's not default Android behavior, not in the View system nor in Compose
j
The complaint is that it isn't android default behavior.
or that there's not a built-in way to implement it broadly if you want to
I'm super aware of the failing
c
@jonathan olds I've been using the simple one liner in the modifier for whatever parent composable the context should clear for (from Stylianos' post)
Copy code
modifier = Modifier.pointerInput(Unit) { detectTapGestures(onTap = { focusManager.clearFocus() }) }
j
Ohh, does that capture button presses, also? I've been add Modifier.clickable (onClick={focusManager.clear()}) to my topmost container, but have had to also the focusmanager call to every button.
o
No, it will not capture button presses, because internally
detectTapGestures
and clickable modifier use main pass, which is handled after children consume their gestures. However according to the Event propagation we could use initial pass, which allows a parent to intercept an event before the child can consume it. So in theory something like this could work:
Copy code
fun Modifier.clearFocusOnTap(): Modifier = composed {
    val focusManager = LocalFocusManager.current
    Modifier.pointerInput(Unit) {
        awaitEachGesture {
            awaitFirstDown(pass = PointerEventPass.Initial)
            val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial)
            if (upEvent != null) {
                focusManager.clearFocus()
            }
        }
    }
}
I have tested it with button & text-field, but I am not sure how it will behave with scrolling and with other elements. Could you please check how it will work for you? Btw, ExposedDropdownMenu uses the same trick 👀
👍 1
c
I prefer to add clearFocus to buttons on a case by case basis. Something like an input to add tags to a post might let you click an "add" button while maintaining focus in the input textbox. Most of my textboxes use keyboard actions to clear focus instead of having something like a "done" button next to the textbox
👍 1
1630 Views