如何在Jetpack Compose中将可滚动项捕捉到屏幕中心
从 Snapper
迁移到 SnapFlingBehavior
之前,我们探讨了Android应用程序开发中一个常见的用例:在fling手势后将可滚动项捕捉到屏幕中心。
为了在Jetpack Compose中实现这一目标,我们使用了之前被存档的"Snapper"库。当官方框架还没有支持时,Snapper提供了一种无缝的解决方案,用于在可滚动布局中实现捕捉行为。如果你错过了那篇文章,你可以在这里阅读。
自那时以来,Jetpack Compose已经发展壮大,好消息是,我们之前使用Snapper库实现的功能现在已经在Jetpack Compose中得到官方支持,引入了SnapFlingBehavior
。这个新的类提供了一个更全面和高效的解决方案,用于在具有动态内容的可滚动列表中将项居中。
在本文中,我们将重新讨论我们在之前的文章中解决的问题,并演示如何从使用Snapper库过渡到官方支持的SnapFlingBehavior
。我们将首先讨论两种方法之间的主要区别,然后提供一步一步的指南,用于在Jetpack Compose项目中实现SnapFlingBehavior
。
转换为SnapFlingBehavior
为了快速回顾一下,让我们来看看我们使用Snapper实现的核心功能。该库允许我们创建一个动态的可滚动列表,在fling手势后将项目捕捉到屏幕中心。当Jetpack Compose没有官方实现此用例的功能时,它是一个很好的解决方案。
通过引入SnapFlingBehavior
,我们现在可以使用Jetpack Compose的官方API实现此捕捉行为。相比Snapper库,SnapFlingBehavior
提供了更大的灵活性和自定义选项。
SnapFlingBehavior
类使项目捕捉到给定位置,使用shortSnapVelocityThreshold
参数区分短/滚动捕捉和长/fling捕捉。此外,它还为不同情况提供了各种动画规格,例如highVelocityAnimationSpec
、lowVelocityAnimationSpec
和snapAnimationSpec
。
现在让我们看看如何利用SnapFlingBehavior来实现我们之前使用Snapper库实现的相同功能。
重新审视我们以前的用例
在我上一篇关于Snapper库的文章中,我们使用了一个动态列表的例子:
@Composable
fun MainContent(
placeholderItems: List<String>
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
text = "Example Horizontal LazyRow"
)
LazyRow(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
items(items = placeholderItems) { itemMessage: String ->
PlaceholderCard(itemMessage)
}
}
}
}
实际效果如下:
我们可以使用 Snapper 实现 fling 行为,如下代码片段所示:
val lazyListState: LazyListState = rememberLazyListState()
val layoutInfo: LazyListSnapperLayoutInfo = rememberLazyListSnapperLayoutInfo(lazyListState)
LazyRow(
modifier = Modifier.fillMaxWidth(),
state = lazyListState,
flingBehavior = rememberSnapperFlingBehavior(lazyListState),
contentPadding = PaddingValues(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
items(items = placeholderItems) { itemMessage: String ->
PlaceholderCard(itemMessage)
}
}
使用SnapFlingBehavior
但是,为了确保在执行 fling 手势后可见项目滚动到屏幕中心,我们不再需要依赖外部库。相反,我们可以利用前面讨论的 SnapFlingBehavior
。
下面的代码片段显示了启用 SnapFlingBehavior
的 MainContent
:
@Composable
fun MainContent(
placeholderItems: List<String>
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
text = "Example Horizontal LazyRow"
)
val listState: LazyListState = rememberLazyListState()
LazyRow(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(horizontal = 32.dp),
verticalAlignment = Alignment.CenterVertically,
state = listState,
flingBehavior = rememberSnapFlingBehavior(listState)
) {
items(placeholderItems) { item: String ->
PlaceholderCard(itemMessage = item)
}
}
}
}
首先,我们使用rememberLazyListState()
函数创建一个LazyListState
,这允许我们存储和管理我们的LazyRow
组件的状态:
val listState: LazyListState = rememberLazyListState()
接下来,我们使用以下属性定义了 LazyRow
组件:
modifier = Modifier.fillMaxWidth()
:确保LazyRow
横跨整个屏幕的宽度。contentPadding = PaddingValues(horizontal = 32.dp)
:在LazyRow
内部应用水平方向为 32.dp 的填充。verticalAlignment = Alignment.CenterVertically
:将LazyRow
中的项在垂直方向上居中对齐。state = listState
:将我们之前定义的LazyListState
设置为LazyRow
的状态。flingBehavior = rememberSnapFlingBehavior(listState)
:通过提供listState
,将SnapFlingBehavior
分配给LazyRow
,从而使列表中的项在 fling 手势后捕捉到中心并最终实现所需的行为。
最终效果如下:
结论
本文中,我们重温了在Jetpack Compose中将可滚动项捕捉到屏幕中央的问题,并从使用Snapper库转换为官方支持的SnapFlingBehavior
。
我们首先看到了我们以前是如何实现动态、可滚动列表的,它在手势滑动后自动将项目捕捉到屏幕中央。随后,我们讨论了使用官方解决方案的相同方法。最后,我们发现在代码长度方面的差异并不大,迁移过程非常简单。