In the JetStream tv app sample, it has a createInitialFocusRestorerModifiers()
function which acts as the focus restorers of a TvLazyRow/Column for its children.
As said from the function's KDoc:
Returns a set of modifiers [FocusRequesterModifiers] which can be used for restoring focus and specifying the initially focused item.
Its usage:
LazyRow(modifier.then(modifiers.parentModifier) {
item1(modifier.then(modifiers.childModifier) {...}
item2 {...}
item3 {...}
...
}
The proper behavior should be the following image. Pressing DPad down should focus to the first item, and up should bring to the last saved state focus child.
Though, the problem here is it does not restore focus on navigation [popBackStack()
] so I tried to integrate the said function with this answer.
Current code:
// var anItemHasBeenFocused: Boolean = false
// var lastFocusedItem: Pair<Int, Int> = ...
TvLazyRow(
modifier = focusRestorerModifiers.parentModifier,
pivotOffsets = PivotOffsets(parentFraction = 0F)
) {
itemsIndexed(items = items) { columnIndex, item ->
val focusRequester = remember { FocusRequester() }
RowItem(
modifier = Modifier
.focusRequester(focusRequester)
.ifElse(
condition = columnIndex == 0,
ifTrueModifier = focusRestorerModifiers.childModifier
)
.onPlaced {
val shouldFocusThisItem = lastFocusedItem.first == rowIndex
&& lastFocusedItem.second == columnIndex
&& !anItemHasBeenFocused
if (shouldFocusThisItem) {
// The stacktrace points here.
focusRequester.requestFocus()
}
}
.onFocusChange {
if(it.isFocused) {
onFocusedChange(item, columnIndex)
}
}
.focusProperties {
if (rowIndex == 0) {
up = FocusRequester.Cancel
} else if (isLastIndex) {
down = FocusRequester.Cancel
}
},
item = item,
isLastIndex = columnIndex == items.lastIndex,
onClick = onNavigateToSecondScreen
)
}
The code worked fine on the first item only, I was able to go back without any errors from the second screen after navigating thru the first item.
When I tried to scroll to the end item of the list - making the first item hidden from the current view - and tried to go to my second screen and immediately pop back from it, the app constantly throws:
FocusRequester is not initialized. Here are some possible fixes:
1. Remember the FocusRequester: val focusRequester = remember { FocusRequester() }
2. Did you forget to add a Modifier.focusRequester() ?
3. Are you attempting to request focus during composition? Focus requests should be made in
response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }
Question: How do I achieve this kind of focus behavior? Being able to combine both initial state focus restorers and navigation state focus restoring?