You can make use of the focusRestoration APIs which were released recently in the alpha version of compose foundation. Reference: saveFocusedChild() and restoreFocusedChild()
You can tap into the focusProperties and when the focus enters the container, you can check if there was a previously saved focused child. If yes, you transfer focus to that child, else, you transfer focus to the first child. While exiting the container, you can save the previously focused child.
You can create the following modifier factory which will abstract away this logic for you:
data class FocusRequesterModifiers(
val parentModifier: Modifier,
val childModifier: Modifier
)
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun createFocusRestorationModifiers(): FocusRequesterModifiers {
val focusRequester = remember { FocusRequester() }
val childFocusRequester = remember { FocusRequester() }
val parentModifier = Modifier
.focusRequester(focusRequester)
.focusProperties {
exit = {
focusRequester.saveFocusedChild()
FocusRequester.Default
}
enter = {
if (!focusRequester.restoreFocusedChild())
childFocusRequester
else
FocusRequester.Cancel
}
}
val childModifier = Modifier.focusRequester(childFocusRequester)
return FocusRequesterModifiers(parentModifier, childModifier)
}
With the above factory in place, you can make use of it in your lazy containers like following:
val modifiers = createFocusRestorationModifiers()
TvLazyRow(
modifier = Modifier.then(modifiers.parentModifier)
) {
item {
Button(
onClick = {},
modifier = Modifier.then(modifiers.childModifier)
) {
Text("My Button 1")
}
}
item { Button(onClick = {}) { Text("My Button 2") } }
item { Button(onClick = {}) { Text("My Button 3") } }
// ...
}
Notice, in the above example usage that we just need to assign the parent modifier to the TvLazyRow
container and the child modifier to the first item. You can choose to assign it to the second or third item as well in case you desire that the second or third item should gain focus for the first time.