返回
Jetpack Compose LazyColumn 中如何仅对首个 StickyHeader 应用动画?
Android
2024-03-10 10:18:18
Jetpack Compose LazyColumn 中首个 StickyHeader 的动画
问题
在 Jetpack Compose 中的 LazyColumn 中,如何仅对首个 StickyHeader 应用动画?目前,动画应用于所有 StickyHeader,这会导致不必要的性能开销和用户体验不佳。
解决方法
可以使用组合 ScrollState.firstVisibleItemIndex、ScrollState.firstVisibleItemScrollOffset 和 ListScrollListener 来确定首个可见 StickyHeader 的索引,然后仅对该 StickyHeader 应用动画。
改进的代码
val listState = rememberLazyListState()
val firstVisibleItemIndex = remember { derivedStateOf { listState.firstVisibleItemIndex } }
val firstVisibleItemScrollOffset = remember { derivedStateOf { listState.firstVisibleItemScrollOffset } }
val topStickyHeaderIndex = remember { mutableStateOf(-1) } // 初始值为无效索引
val scrollChangeListener = remember {
object : ListScrollListener {
override fun onScrollStateChanged(state: ScrollState, previousState: ScrollState) {
super.onScrollStateChanged(state, previousState)
if (state.isScrollInProgress) {
// 跟踪正在滚动的方向
val direction = if (state.firstVisibleItemIndex < previousState.firstVisibleItemIndex) ScrollDirection.UP else ScrollDirection.DOWN
when (direction) {
ScrollDirection.UP -> {
// 向上滚动
if (topStickyHeaderIndex.value == -1) {
// 尚未确定首个 StickyHeader,查找它
var index = 0
while (index < listState.layoutInfo.totalItemsCount) {
if (listState.isItemSticky(index)) {
topStickyHeaderIndex.value = index
break
}
index++
}
}
}
ScrollDirection.DOWN -> {
// 向下滚动
if (topStickyHeaderIndex.value >= 0) {
topStickyHeaderIndex.value = -1
}
}
}
}
}
}
}
LazyColumn(
state = listState,
modifier = modifier.nestedScroll(nestedScrollConnection).onScroll(scrollChangeListener)
) {
categories.forEachIndexed { index, category ->
stickyHeader {
SessionCard(
firstVisibleItemIndex = firstVisibleItemIndex.value,
firstVisibleItemScrollOffset = firstVisibleItemScrollOffset.value,
scale = if (index == topStickyHeaderIndex.value) scale.value else 1f,
index = index
)
}
items(category.items) { text ->
CategoryItem(text)
}
}
}
结论
通过使用 LazyColumn 中提供的功能,我们可以有效地仅对首个 StickyHeader 应用动画。这可以显着提高性能并改善用户体验。
常见问题解答
-
是否可以仅对特定的 StickyHeader 应用动画,而不是首个?
- 是,可以通过修改代码来实现。您需要确定您要应用动画的 StickyHeader 的索引,并相应地调整 if 语句。
-
如果 StickyHeader 可以出现在其组的任何位置,该怎么办?
- 您需要修改代码以检查每个项是否是 StickyHeader。您可以通过调用 listState.isItemSticky() 来做到这一点。
-
是否有任何替代方法?
- 有,您可以使用一个单独的 NestedScrollConnection 来跟踪首个可见的 StickyHeader。但是,这种方法可能不太高效。
-
这种方法是否与不同类型的 StickyHeader 兼容?
- 是,这种方法与任何类型的 StickyHeader 兼容,只要它们是由 LazyColumn 管理的。
-
如何进一步优化动画性能?
- 您可以通过使用 AnimatedContent 来仅在 StickyHeader 更改时更新动画来进一步优化性能。