You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Jetpack Compose TV导航返回时焦点恢复问题求助

解决方案

有,你可以通过保存LazyGrid的滚动状态和点击记录,实现返回时自动恢复焦点,不用给每个卡片单独写复杂的焦点恢复逻辑,具体实现如下:

实现步骤

  1. 用rememberSaveable保存LazyGrid的滚动状态,确保从详情页返回时,列表位置不会重置。
  2. 借助Navigation的SavedStateHandle存储最后点击的卡片索引,跨页面持久化数据。
  3. 在列表项中添加简单的焦点请求逻辑,返回时自动滚动到目标卡片并聚焦。

修改后的完整代码

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()
            NavHost(
                navController = navController,
                startDestination = "Home"
            ) {
                composable("Home") { backStackEntry ->
                    val savedState = backStackEntry.savedStateHandle
                    // 保存最后点击的卡片索引,默认-1表示无记录
                    val lastClickedIndex = savedState.getStateFlow<Int>("clickedIndex", -1)
                        .collectAsStateWithLifecycle()

                    val cardList = rememberSaveable { List(100) { "Card $it" } }
                    // 保存LazyGrid的滚动状态
                    val gridState = rememberSaveable(saver = LazyGridState.Saver) {
                        LazyGridState()
                    }

                    LazyVerticalGrid(
                        state = gridState,
                        modifier = Modifier.fillMaxSize(),
                        columns = GridCells.Adaptive(minSize = 70.dp),
                        contentPadding = PaddingValues(horizontal = 40.dp),
                        horizontalArrangement = Arrangement.spacedBy(20.dp),
                        verticalArrangement = Arrangement.spacedBy(20.dp)
                    ) {
                        itemsIndexed(
                            items = cardList,
                            key = { index, _ -> index }
                        ) { index, cardText ->
                            var isFocused by remember { mutableStateOf(false) }
                            val focusRequester = remember { FocusRequester() }

                            Box(
                                modifier = Modifier
                                    .focusRequester(focusRequester)
                                    .onFocusChanged { isFocused = it.hasFocus }
                                    .size(70.dp)
                                    .background(Color.Red)
                                    .border(2.dp, if (isFocused) Color.White else Color.Transparent)
                                    .clickable {
                                        // 点击时记录索引
                                        savedState["clickedIndex"] = index
                                        navController.navigate("Details")
                                    }
                                    .focusable(),
                                contentAlignment = Alignment.Center
                            ) {
                                Text(text = cardText)
                            }

                            // 返回时自动聚焦目标卡片
                            LaunchedEffect(lastClickedIndex.value) {
                                if (lastClickedIndex.value == index) {
                                    gridState.scrollToItem(index)
                                    focusRequester.requestFocus()
                                    // 清除记录,避免重复触发
                                    savedState["clickedIndex"] = -1
                                }
                            }
                        }
                    }
                }
                composable("Details") {
                    Box(
                        modifier = Modifier.fillMaxSize(),
                        contentAlignment = Alignment.Center
                    ) {
                        Button(onClick = { navController.popBackStack() }) {
                            Text("Go back")
                        }
                    }
                }
            }
        }
    }
}

关键细节

  • LazyGridState.Saver:保证滚动状态在页面导航、重建时不丢失,不用手动处理滚动位置。
  • SavedStateHandle:官方推荐的跨导航页面数据持久化方式,比自己存全局状态更可靠。
  • FocusRequester:每个卡片仅需一个简单的焦点请求器,逻辑集中且不复杂,不算单独的焦点恢复器。
  • LaunchedEffect:只在返回且有有效索引时触发一次,滚动到目标位置并请求焦点,完成后清除索引防止重复执行。

内容的提问来源于stack exchange,提问作者Corentin Zuber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:15:02