LazyColumn的滑动没有类似Recyclerview的回调监听,可以通过LazyListState来做判断 LazyListState中主要的成员有:
- isScrollInProgress 控件是否处于滑动状态
- firstVisibleItemIndex 列表第一个可见项的下标
- firstVisibleItemScrollOffset 列表第一个可见项的滑动偏移,向上滑动(即正方向)时变大,向下时变小
- layoutInfo 包含列表当前显示的布局状态的相关信息。例如当前显示的item信息,item总数,列表宽高等
思路:
- 滑动开始与结束:在isScrollInProgress为true(即滑动状态下)的代码块中启动一个key为Unit的DisposableEffect(Unit单例不变,不会导致Effect重组),DisposableEffect进入组合(即滑动状态判断条件成立)后会启动一次,并且在退出组合后会调用onDispose,可以以此做为开始滑动与结束滑动的监听
- 滑动方向与距离:通过firstVisibleItemIndex和firstVisibleItemScrollOffset做判断 代码如下:
@Composable
fun AWidget() {
val lazyListState = rememberLazyListState()
if (lazyListState.isScrollInProgress) {
//进入组合后只会启动一次,
DisposableEffect(Unit) {
Log.d(TAG, "start scroll")
onDispose {
Log.d(TAG, "stop scroll")
}
}
//记录上一次第一个可见item的滑动偏移
var lastFirstVisibleItemScrollOffset by remember {
mutableStateOf(lazyListState.firstVisibleItemScrollOffset)
}
//记录上一次第一个可见item下标
var lastFirstVisibleItemIndex by remember {
mutableStateOf(lazyListState.firstVisibleItemIndex)
}
run {
val currentFirstVisibleItemIndex = lazyListState.firstVisibleItemIndex
//手指向上滑动(即正方向)时offset会变大,向下时变小
val currentFirstVisibleItemScrollOffset = lazyListState.firstVisibleItemScrollOffset
//第一个可见的item改变了
if (currentFirstVisibleItemIndex != lastFirstVisibleItemIndex) {
if (currentFirstVisibleItemIndex < lastFirstVisibleItemIndex) {
Log.d(TAG, "向下滑动↓ ")
} else if (currentFirstVisibleItemIndex > lastFirstVisibleItemIndex) {
Log.d(TAG, "向上滑动↑")
}
//更新记录的值,退出run代码块
lastFirstVisibleItemIndex = currentFirstVisibleItemIndex
lastFirstVisibleItemScrollOffset = currentFirstVisibleItemScrollOffset
return@run
}
//第一个可见item当前的offset - 上一次记录的offset
val offset =
currentFirstVisibleItemScrollOffset - lastFirstVisibleItemScrollOffset
if (offset < 0) {
Log.d(TAG, "向下滑动↓ $offset")
} else if (offset > 0) {
Log.d(TAG, "向上滑动↑ $offset")
}
//记录第一个可见item当前的offset
lastFirstVisibleItemScrollOffset = currentFirstVisibleItemScrollOffset
}
}
//将lazyListState赋值给LazyColunm
LazyColumn(Modifier.fillMaxSize(), state = lazyListState) {
items(100) {
Text(
text = "$it",
Modifier
.fillMaxWidth()
.height(140.dp)
)
}
}
}