Status Update
Comments
hv...@gmail.com <hv...@gmail.com> #2
Actually onFocusChanged is always called, but it.isFocused
is always false
in the Faulty version.
so...@google.com <so...@google.com>
hv...@gmail.com <hv...@gmail.com> #3
Now I found a mention of the order of modifiers in
ra...@google.com <ra...@google.com>
ra...@google.com <ra...@google.com> #4
Thanks for filing this bug.
This is working as expected. Focus modifiers are ordered. The focus modifier holds the focus state. When focus state changes, it calls all focus modifers preceeding it. (Also those on a parent layout node) until it sees another focus modifier.
We need to update the documentation. I'm keeping this bug open to track the documentation change needed.
That said, I want to hear your thoughts/frustrations about the current API. Would you prefer that the order didn't matter? We could do that if we only allow one focus modifier per layout node. (And maybe use the modifier order to pick one modifer if the user specifies multiple).
hv...@gmail.com <hv...@gmail.com> #5
I understand the need for multiple onFocusChanged { ... }
modifiers, but I don't see how multiple focusModifier()
s would work.
I tried it out and if I use:
Modifier
.onFocusChanged(firstFn)
.focusModifier()
.onFocusChanged(secondFn()
.focusModifier()
only firstFn
is called. I see that if both would be called, that would enable abstracting and passing around groups of .onFocusChanged {}.focusModifier()
pairs.
On the other hand this code:
Modifier
.onFocusChanged(firstFn)
.onFocusChanged(secondFn()
.focusModifier()
calls both functions and still allows for onFocusChanged
's to be passed around, and I think this is valuable. In this case the behavior is also quite straight forward: The onFocusChanged
need to be followed by a .focusModifier()
to be active.
Did I miss some use case you had in mind for multiple focus modifiers?
ra...@google.com <ra...@google.com> #6
I can't think of an actual use-case for multiple focusModifiers per layout node, but the nature of our system allows the addition of multiple focus modifiers. So this is not a realistic scenario, but if we want to make your example work, you would need another focus requester. Focus requesters are similar to onFocusChanged modifiers. Both of them request/observe the next focusModifier. Your example could be changed to:
Modifier
.focusRequester(focusRequester1)
.onFocusChanged { ... }
.focusModifier()
.border(10.dp)
.focusRequester(focusRequester2)
.onFocusChanged { ... }
.focusModifier()
Now, calling focusRequester1.requestFocus() will change the state of the first focusModifier. focusRequester2.requestFocus() will change the state of the second focusModifier.
I guess the way to think of it is that the focus state is part of the focus modifier. When you call requestFocus(), the focusModifier's state is changed to "focused".
hv...@gmail.com <hv...@gmail.com> #7
Thank you for the explanation! I tried that out and it meets expectations. One thing to note is that the platform provided d-pad navigation brings focus to the first focusRequester.
ra...@google.com <ra...@google.com> #8
Oh, I didn't realize that you were using the d-pad. Yes, the d-pad will bring focus to the first focus modifier. You can think of the second modifier as a child of the first, imagine they were defined across different composables:
@Composable
fun FancyFocusableBox(){
FocusableBox(Modifier
.onFocusChanged {...}
.focusModifier()
)
}
@Composable
fun FocusableBox(modifier: Modifier){
Box(modifier
.onFocusChanged {...}
.focusModifier()
)
}
So coming back to your example, the d-pad will initially bring focus to the first modifier. If you then press d-pad center, focus will move to the next modifier.
ap...@google.com <ap...@google.com> #9
Branch: androidx-main
commit 94f406c27f67b2298be236e1c7f7ce11bf532785
Author: Ralston Da Silva <ralu@google.com>
Date: Wed Jun 09 14:44:08 2021
Focus Cleanup
Add Samples
Update Documentation
Remove internal references from public docs
Bug: 170154986
Bug: 190386715
Bug: 186567354
Bug: 168510304
Test: N/A
Relnote: "Removed deprecated experimental `FocusManager#moveFocusIn` and `FocusManager#moveFocusOut`"
Change-Id: I227d79e985d993d52d383d22439abaecbce9f593
M compose/ui/ui/api/public_plus_experimental_1.0.0-beta10.txt
M compose/ui/ui/api/public_plus_experimental_current.txt
M compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/UiDemos.kt
A compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CaptureFocusDemo.kt
M compose/ui/ui/integration-tests/ui-demos/src/main/java/androidx/compose/ui/demos/focus/CustomFocusOrderDemo.kt
M compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/FocusSamples.kt
A compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/KeyInputSamples.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/key/Key.android.kt
M compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/key/KeyEvent.android.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusChangedModifier.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusModifier.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusOrderModifier.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequester.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusRequesterModifier.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusState.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusTraversal.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/Key.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/KeyEvent.kt
M compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/KeyInputModifier.kt
Description
Jetpack Compose release version:
1.0.0-beta04
Android Studio Build:
#AI-203.7148.57.2031.7242491
Steps to Reproduce:
focusModifier()
beforeonFocusChanged {}
onFocusChanged
is not called even if the element reaches focusSample project that demonstrates the bug can be found athttps://github.com/hvrauhal/compose-focusmodifier-bug
In the following example
BoxWithFocusModifiersInFaultyOrder
is the not working version: