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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 01:22:24