Jetpack Compose中LazyColumn不可见item如何获取焦点并触发滚动?
问题解决方案
问题根因
LazyColumn 仅会加载可视区域附近的子项,子项滚出可视区域后会被回收销毁。你当前的实现逻辑是等子项获取焦点后再触发滚动,但已经被回收的子项无法接收焦点事件,onFocused 回调永远不会触发,自然无法将对应子项重新滚动到可视区域,陷入逻辑死循环。
修复方案
使用 Compose 原生提供的 bringIntoViewRequester 修饰符自动处理焦点项滚入可视区的逻辑,无需手动调用 scrollToItem,代码改动最小且兼容性更好。
修改后完整代码
import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.foundation.relocation.bringIntoViewRequester @Composable fun ScrollableList(modifier: Modifier = Modifier) { val scrollState = rememberLazyListState() LazyColumn( state = scrollState, modifier = Modifier.padding(5.dp), verticalArrangement = Arrangement.spacedBy(5.dp) ) { itemsIndexed(items = (0..10).toList()) { index, item -> FocusableBox( title = "ScrollBox-$index" ) } } } @Composable fun FocusableBox( title: String, onFocused: (Boolean) -> Unit = {}, requester: FocusRequester = FocusRequester(), modifier: Modifier = Modifier ) { // 新增 BringIntoViewRequester val bringIntoViewRequester = remember { BringIntoViewRequester() } val scope = rememberCoroutineScope() var boxColor by remember { mutableStateOf(Color.White) } var focused by remember { mutableStateOf(false) } Box( Modifier .bringIntoViewRequester(bringIntoViewRequester) // 注意顺序:要放在focus相关修饰符前面 .focusRequester(requester) .onFocusChanged { boxColor = if (it.isFocused) Color.Green else Color.Gray focused = it.isFocused onFocused(it.isFocused) // 拿到焦点时请求将当前项滚入可视区域 if (it.isFocused) { scope.launch { bringIntoViewRequester.bringIntoView() } } } .focusable() .background(boxColor) .zIndex(if (focused) 1f else 0f) ) { Text( text = title, modifier = Modifier.padding(30.dp), color = Color.White, style = MaterialTheme.typography.subtitle2 ) } }
注意事项
- 修饰符顺序不能调换,
bringIntoViewRequester必须放在onFocusChanged、focusable等焦点相关修饰符之前 - 原生逻辑会自动适配滚动位置,避免滚动越界等异常问题,自带平滑滚动效果
内容的提问来源于stack exchange,提问作者TangSir
相关产品推荐
相关产品推荐

