Jetpack Compose 导航页面间焦点丢失问题排查与解决
Jetpack Compose 返回页面保留焦点问题解决
问题原因
默认情况下,Jetpack Compose 的 NavHost 在从详情页返回主页面时,会重组 MainScreen 组件,原列表项的焦点状态会随着组件重建而丢失——因为重组后所有可组合项都会重新初始化,之前的焦点信息没有被持久化保存。
简洁实现方案
1. 在ViewModel中持久化选中项索引
给主页面的ViewModel添加状态变量,记录最后选中的列表项索引:
class MainScreenViewModel : ViewModel() { val lastSelectedItemIndex = mutableStateOf(-1) fun setLastSelectedIndex(index: Int) { lastSelectedItemIndex.value = index } }
2. 点击列表项时保存索引并导航
在MainScreen的列表项中,点击时先记录当前索引到ViewModel,再执行导航:
// 以LazyColumn实现的列表为例 LazyColumn { itemsIndexed(itemsList) { index, item -> val focusRequester = remember { FocusRequester() } Box( modifier = Modifier .focusRequester(focusRequester) .focusable() .clickable { // 保存选中索引 mainScreenViewModel.setLastSelectedIndex(index) // 跳转详情页 mainNavController.navigate(MainDestinations.AccessibilityScreen) } ) { Text(text = item.content) } // 页面重组后自动恢复焦点 LaunchedEffect(mainScreenViewModel.lastSelectedItemIndex) { if (mainScreenViewModel.lastSelectedItemIndex.value == index) { focusRequester.requestFocus() } } } }
3. 优化导航行为(可选)
添加launchSingleTop = true,避免返回时重复创建MainScreen实例,减少不必要的重组:
private fun handleClick() { mainNavController.navigate(MainDestinations.AccessibilityScreen) { launchSingleTop = true } }
核心逻辑说明
- 利用ViewModel的生命周期特性,确保选中索引在页面重建后不丢失
- 通过
FocusRequester配合LaunchedEffect,在页面重组完成后自动将焦点定位到之前选中的列表项 - 可选的导航参数优化可以进一步提升页面返回时的性能
内容的提问来源于stack exchange,提问作者Raluca Lucaci
相关产品推荐
相关产品推荐

