Jetpack Compose TV应用返回主界面时恢复焦点问题排查
解决Jetpack Compose TV返回主界面后焦点丢失问题
问题根源
你用的是Compose TV 1.0.0-alpha06,这个早期测试版本的嵌套TvLazyColumn+TvLazyRow存在焦点恢复bug——从详情页返回时,系统不会自动把焦点还给之前选中的列表项,必须手动触发焦点请求。你之前试的rememberTvLazyListState只能保存滚动位置,管不了焦点;设置唯一键也解决不了这个版本的焦点逻辑问题。
可行解决方案
1. 手动记录焦点位置,返回时主动请求焦点
额外保存焦点所在的行索引和项索引,返回主界面时通过FocusRequester主动让目标项获取焦点:
// 主界面中保存焦点坐标 var focusedRowIdx by remember { mutableIntStateOf(0) } var focusedItemIdx by remember { mutableIntStateOf(0) } // 存储每个列表项的FocusRequester,用行列索引做键 val focusRequesters = remember { mutableMapOf<Int, MutableMap<Int, FocusRequester>>() } TvLazyColumn(state = rememberTvLazyListState()) { itemsIndexed(categories) { rowIdx, category -> // 初始化当前行的FocusRequester Map if (!focusRequesters.containsKey(rowIdx)) { focusRequesters[rowIdx] = mutableMapOf() } TvLazyRow( modifier = Modifier.onFocusChanged { if (it.isFocused) focusedRowIdx = rowIdx } ) { itemsIndexed(category.items) { itemIdx, item -> // 初始化当前项的FocusRequester val requester = focusRequesters[rowIdx]?.getOrPut(itemIdx) { FocusRequester() } ?: FocusRequester() ItemCard( item = item, modifier = Modifier .focusRequester(requester) .onFocusChanged { if (it.isFocused) focusedItemIdx = itemIdx } .focusable() ) { navController.navigate("detail/${item.id}") } } } } } // 监听返回事件,恢复焦点 LaunchedEffect(navController.currentBackStackEntry) { val currentRoute = navController.currentBackStackEntry?.destination?.route if (currentRoute == "main") { // 延迟确保列表完成布局,避免请求焦点失败 delay(100) focusRequesters[focusedRowIdx]?.get(focusedItemIdx)?.requestFocus() } }
2. 升级Compose TV版本
1.0.0-alpha06是非常早期的版本,后续的1.0.0-beta01及以上版本已经修复了大量焦点相关的bug,包括这种返回时焦点丢失的问题。直接升级版本大概率能解决问题,这是最省心的方案。
3. 强制触发列表焦点
如果暂时不想升级版本,也可以在返回主界面时,让TvLazyColumn滚动到之前的位置后,强制触发焦点:
val columnState = rememberTvLazyListState() TvLazyColumn(state = columnState) { // 列表内容... } LaunchedEffect(navController.currentBackStackEntry) { if (navController.currentBackStackEntry?.destination?.route == "main") { // 滚动到之前的行 columnState.scrollToItem(focusedRowIdx) delay(150) // 通过遍历或者焦点请求器触发焦点 focusRequesters[focusedRowIdx]?.get(focusedItemIdx)?.requestFocus() } }
注意点
- 保存焦点位置时,要在
onFocusChanged的isFocused为true时记录,避免误触。 FocusRequester要通过remember或者存入Map持有,不要在重组时重复创建,否则会失效。
内容的提问来源于stack exchange,提问作者Tim Schmidt
相关产品推荐
相关产品推荐

