Android Jetpack Compose TV导航返回时焦点恢复问题求助
解决方案
有,你可以通过保存LazyGrid的滚动状态和点击记录,实现返回时自动恢复焦点,不用给每个卡片单独写复杂的焦点恢复逻辑,具体实现如下:
实现步骤
- 用
rememberSaveable保存LazyGrid的滚动状态,确保从详情页返回时,列表位置不会重置。 - 借助Navigation的
SavedStateHandle存储最后点击的卡片索引,跨页面持久化数据。 - 在列表项中添加简单的焦点请求逻辑,返回时自动滚动到目标卡片并聚焦。
修改后的完整代码
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
相关产品推荐
相关产品推荐

