Jetpack Compose中LazyVerticalGrid返回后恢复焦点问题求助
LazyVerticalGrid返回后恢复焦点的实现方案
完全可以实现返回页面后让之前的焦点项重新获取焦点,你的错误是因为在Composition阶段直接调用焦点请求,此时组件还未完成布局绑定,导致FocusRequester未初始化。下面是具体的解决步骤和代码示例:
核心问题分析
- 你在
itemsIndexed的代码块中直接调用focusRequester.requestFocus(),这属于Composition过程中的同步操作,此时组件还没完成布局,FocusRequester还没和对应的Column绑定,所以触发初始化错误。 - 每个item内部的FocusRequester是局部变量,页面重组(比如返回时)会重新创建,无法追踪之前的焦点项。
解决步骤
- 持久化焦点索引:用
rememberSaveable保存上次获得焦点的项索引,确保从其他页面返回时不会丢失。 - 全局管理FocusRequester:用
mutableStateListOf存储每个item的FocusRequester,保证重组时引用不失效。 - 正确时机请求焦点:用
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
相关产品推荐
相关产品推荐

