So I have spent some time looking at this bug, but it seems really non-trivial to solve. As I understand, we want to 1. We want to automatically focus on the currently selected item 2. We want to retain natural order of scrolling (upwards or downwards) whenever the user starts interacting with the list. From my investigations, this has proven to be non trivial, because even when we force the traversal order to prioritize the selected item, talkback still focuses on the first item in the list. I tested this outside of Fenix, using the [MenuWithScrollStateSample](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/samples/src/main/java/androidx/compose/material/samples/MenuSamples.kt;l=59-84?q=MenuWithScrollState&ss=androidx%2Fplatform%2Fframeworks%2Fsupport) in Andoid source. I adapted it to look similar to what we are doing - forcing the traversal order, and pre-selecting an item somewhere in the middle, and talkback always stayed on the first visible item in the list. The only hack that seemed to work intermittently was adding a focus requester on the selected item, and then add an arbitrary delay (1 second in my case) before scrolling to the selected item, and requesting focus. The ``` ``` I had a look at a bunch of apps, and I don't quite have any app that does this. Most of them list the selected item first on the list, and then create a section for the "rest of the list". That sems
Bug 1919104 Comment 6 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
So I have spent some time looking at this bug, but it seems really non-trivial to solve. As I understand, we want to 1. We want to automatically focus on the currently selected item 2. We want to retain natural order of scrolling (upwards or downwards) whenever the user starts interacting with the list. From my investigation, this has proven to be non trivial, because even when we force the traversal order to prioritize the selected item, talkback still focuses on the first item in the list. I tested this outside of Fenix, using the [MenuWithScrollStateSample](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/samples/src/main/java/androidx/compose/material/samples/MenuSamples.kt;l=59-84?q=MenuWithScrollState&ss=androidx%2Fplatform%2Fframeworks%2Fsupport) in Andoid source. I adapted it to look similar to what we are doing - forcing the traversal order, and pre-selecting an item somewhere in the middle, and talkback always stayed on the first visible item in the list. The only hack that seemed to work intermittently was adding a focus requester on the selected item, and then add an arbitrary delay (1 second in my case) before scrolling to the selected item, and requesting focus. This is definitely something that I do not recommend but I wanted to demonstrate that this seems to be a platform problem with the way talkback works. ```kotlin @Preview @Composable fun Test() { val selectedIndex = 18 val focusRequester = FocusRequester() var expanded by remember { mutableStateOf(false) } val scrollState = rememberScrollState() Box( modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.TopStart) ) { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Localized description") } DropdownMenu( modifier = Modifier.requiredSize(width = 300.dp, height = 400.dp), expanded = expanded, onDismissRequest = { expanded = false }, scrollState = scrollState ) { repeat(30) { index -> val isSelected = index == selectedIndex DropdownMenuItem( modifier = Modifier .then( if (isSelected) { Modifier.focusRequester(focusRequester) } else { Modifier } ) .focusable(enabled = true) .selectable( selected = isSelected, onClick = {} ), onClick = { /* Handle item! */ }, text = { Text("Item $index") } ) } } LaunchedEffect(expanded) { if (expanded) { // Scroll to the selected index scrollState.scrollTo(selectedIndex) delay(1000) // no please! focusRequester.requestFocus() } } } } ```
So I have spent some time looking at this bug, but it seems really non-trivial to solve. As I understand, we want to 1. We want to automatically focus on the currently selected item 2. We want to retain natural order of scrolling (upwards or downwards) whenever the user starts interacting with the list. From my investigation, this has proven to be non trivial, because even when we force the traversal order to prioritize the selected item, talkback still focuses on the first item in the list. I tested this outside of Fenix, using the [MenuWithScrollStateSample](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/samples/src/main/java/androidx/compose/material/samples/MenuSamples.kt;l=59-84?q=MenuWithScrollState&ss=androidx%2Fplatform%2Fframeworks%2Fsupport) in Andoid source. I adapted it to look similar to what we are doing - forcing the traversal order, and pre-selecting an item somewhere in the middle, and talkback always stayed on the first visible item in the list. The only hack that seemed to work intermittently was adding a focus requester on the selected item, and then add an arbitrary delay (1 second in my case) before scrolling to the selected item, and requesting focus. This is definitely something that I do not recommend but I wanted to demonstrate that this seems to be a platform problem with the way talkback works. ``` @Preview @Composable fun Test() { val selectedIndex = 18 val focusRequester = FocusRequester() var expanded by remember { mutableStateOf(false) } val scrollState = rememberScrollState() Box( modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.TopStart) ) { IconButton(onClick = { expanded = true }) { Icon(Icons.Default.MoreVert, contentDescription = "Localized description") } DropdownMenu( modifier = Modifier.requiredSize(width = 300.dp, height = 400.dp), expanded = expanded, onDismissRequest = { expanded = false }, scrollState = scrollState ) { repeat(30) { index -> val isSelected = index == selectedIndex DropdownMenuItem( modifier = Modifier .then( if (isSelected) { Modifier.focusRequester(focusRequester) } else { Modifier } ) .focusable(enabled = true) .selectable( selected = isSelected, onClick = {} ), onClick = { /* Handle item! */ }, text = { Text("Item $index") } ) } } LaunchedEffect(expanded) { if (expanded) { // Scroll to the selected index scrollState.scrollTo(selectedIndex) delay(1000) // no please! focusRequester.requestFocus() } } } } ```