Android Jetpack Compose列表滚动到指定项

前言

在 Jetpack Compose 中,Row 本身 不支持滚动到某一项

如果你希望实现横向滚动的布局,并且能够滚动到指定项,你应该使用 LazyRow(而不是普通的 Row)。

注意

普通 Row 放在 HorizontalScrollableModifier.horizontalScroll() 中虽然可以横向滚动,但 无法精确滚动到某一项,因为没有类似 scrollToItem 的 API。

此时只能通过 scrollState.animateScrollTo(value: Int) 手动计算像素位置,非常不推荐。

完整实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Composable
fun EchoWordTitleTabComp(
titleArr: List<String>,
selectTitle: String = "",
onClick: (String) -> Unit
) {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
LazyRow(
state = listState,
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
items(titleArr) { title ->
Box(modifier = Modifier.clickableDebounced {
onClick(title)
}) {
TitleItemComp(title, isSelected = title == selectTitle)
}
}
}
LaunchedEffect(selectTitle) {
delay(100)
scope.launch {
if (selectTitle.isNotEmpty()) {
val index = titleArr.indexOf(selectTitle)
val visibleItems = listState.layoutInfo.visibleItemsInfo
val firstVisibleIndex = visibleItems.firstOrNull()?.index ?: 0
val lastVisibleIndex = visibleItems.lastOrNull()?.index ?: 0
//不在显示区域内再滚动
if (index !in firstVisibleIndex..lastVisibleIndex) {
listState.scrollToItem(index)
}
}
}
}
}

滚动到指定索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LaunchedEffect(selectTitle) {
delay(100)
scope.launch {
if (selectTitle.isNotEmpty()) {
val index = titleArr.indexOf(selectTitle)
val visibleItems = listState.layoutInfo.visibleItemsInfo
val firstVisibleIndex = visibleItems.firstOrNull()?.index ?: 0
val lastVisibleIndex = visibleItems.lastOrNull()?.index ?: 0
//不在显示区域内再滚动
if (index !in firstVisibleIndex..lastVisibleIndex) {
listState.scrollToItem(index)
}
}
}
}

LazyRow和Row

LazyRow/LazyColumnRow/Column怎样选择?

个人建议:

只要列表的数据会超出显示区域的,都建议使用LazyRow/LazyColumn,他只会渲染显示的部分,使用Row/Column会出现卡顿。