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

Jetpack Compose中LazyVerticalGrid返回后恢复焦点问题求助

LazyVerticalGrid返回后恢复焦点的实现方案

完全可以实现返回页面后让之前的焦点项重新获取焦点,你的错误是因为在Composition阶段直接调用焦点请求,此时组件还未完成布局绑定,导致FocusRequester未初始化。下面是具体的解决步骤和代码示例:

核心问题分析

  1. 你在itemsIndexed的代码块中直接调用focusRequester.requestFocus(),这属于Composition过程中的同步操作,此时组件还没完成布局,FocusRequester还没和对应的Column绑定,所以触发初始化错误。
  2. 每个item内部的FocusRequester是局部变量,页面重组(比如返回时)会重新创建,无法追踪之前的焦点项。

解决步骤

  1. 持久化焦点索引:用rememberSaveable保存上次获得焦点的项索引,确保从其他页面返回时不会丢失。
  2. 全局管理FocusRequester:用mutableStateListOf存储每个item的FocusRequester,保证重组时引用不失效。
  3. 正确时机请求焦点:用LaunchedEffect在Composition完成后异步请求焦点,避免初始化问题。

完整代码示例

@Composable
fun FocusGridScreen(navController: NavController) {
    // 保存上次获得焦点的项索引,跨页面返回时保留状态
    val lastFocusedIndex = rememberSaveable { mutableStateOf(-1) }
    // 为每个item创建并存储FocusRequester,重组时保持引用
    val focusRequesters = remember {
        mutableStateListOf<FocusRequester>().apply {
            repeat(5) { add(FocusRequester()) }
        }
    }
    val items = listOf(1, 2, 3, 4, 5)

    LazyVerticalGrid(columns = GridCells.Fixed(4)) {
        itemsIndexed(items) { index, item ->
            Column(
                modifier = Modifier
                    .onFocusChanged { state ->
                        // 记录当前获得焦点的项索引
                        if (state.isFocused) {
                            lastFocusedIndex.value = index
                        }
                    }
                    .focusRequester(focusRequesters[index])
                    .focusable() // 必须添加此修饰符,让组件具备焦点能力
                    .clickable {
                        // 导航至目标页面
                        navController.navigate("detail_screen")
                    }
                    .padding(16.dp)
                    .background(if (lastFocusedIndex.value == index) Color.LightGray else Color.White)
            ) {
                Text(text = item.toString(), fontSize = 20.sp)
            }
        }
    }

    // 当焦点索引变化(包括页面返回时),异步请求焦点
    LaunchedEffect(lastFocusedIndex.value) {
        if (lastFocusedIndex.value != -1) {
            // 延迟确保布局完成,也可以用withContext(Dispatchers.Main) + awaitIdle()
            delay(100)
            focusRequesters[lastFocusedIndex.value].requestFocus()
        }
    }
}

关键细节说明

  • focusable()修饰符:必须添加,否则组件无法成为焦点目标,FocusRequester也无法生效。
  • LaunchedEffect的作用:它会在Composition完成后执行,此时组件已经完成布局,FocusRequester已经和组件绑定,不会触发未初始化错误。
  • rememberSaveable:相比remember,它会将状态持久化到Bundle中,页面销毁重建(比如返回时)不会丢失数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:45:05