jetpack compose:滚动到底部侦听器(列表末尾)

Abd*_*ؤمن 18 android android-jetpack-compose android-jetpack-compose-lazy-column

我想知道当到达列表底部时是否可以让观察者进入@Compose函数内部(类似于recyclerView.canScrollVertically(1)

提前致谢。

小智 22

对我来说,最好和最简单的解决方案是添加LaunchedEffect为我的最后一项LazyColumn

LazyColumn(modifier = Modifier.fillMaxSize()) {
    items(someItemList) { item ->
        MyItem(item = item)
    }
    item {
        LaunchedEffect(true) {
            //Do something when List end has been reached
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是最简单、最优雅的解决方案。有什么缺点吗?从我在 LaunchedEffect 的文档中看到的情况来看,当 LaunchedEffect 离开组合时,启动的协程将被取消。 (2认同)
  • 另一个缺点是当最后一个项目立即可见时,例如,当您的项目列表在填充之前从网络加载时,最后一个项目已经触发。 (2认同)

Abd*_*ؤمن 19

你可以使用rememberLazyListState()和比较

scrollState.layoutInfo.visibleItemsInfo.lastOrNull()?.index == scrollState.layoutInfo.totalItemsCount - 1
Run Code Online (Sandbox Code Playgroud)

如何使用示例

首先添加上述命令作为扩展名(例如extensions.kt文件):

fun LazyListState.isScrolledToEnd() = layoutInfo.visibleItemsInfo.lastOrNull()?.index == layoutInfo.totalItemsCount - 1
Run Code Online (Sandbox Code Playgroud)

然后在下面的代码中使用它:

@Compose
fun PostsList() {
  val scrollState = rememberLazyListState()

  LazyColumn(
    state = scrollState,),
  ) {
     ...
  }

  // observer when reached end of list
  val endOfListReached by remember {
    derivedStateOf {
      scrollState.isScrolledToEnd()
    }
  }

  // act when end of list reached
  LaunchedEffect(endOfListReached) {
    // do your stuff
  }
}

Run Code Online (Sandbox Code Playgroud)


Gab*_*tti 9

从您开始,1.4.0-alpha03您可以使用它LazyListState#canScrollForward来检查您是否位于列表的末尾。

就像是:

val state = rememberLazyListState()
val isAtBottom = !state.canScrollForward

LaunchedEffect(isAtBottom){
    if (isAtBottom) doSomething()
}
Run Code Online (Sandbox Code Playgroud)

在此版本之前,您可以使用LazyListState#layoutInfo包含有关可见项目的信息的 。请注意您应该使用derivedStateOf以避免冗余重组。

使用一些东西:

@Composable
private fun LazyListState.isAtBottom(): Boolean {

    return remember(this) {
        derivedStateOf {
            val visibleItemsInfo = layoutInfo.visibleItemsInfo
            if (layoutInfo.totalItemsCount == 0) {
                false
            } else {
                val lastVisibleItem = visibleItemsInfo.last()
                val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset

                (lastVisibleItem.index + 1 == layoutInfo.totalItemsCount &&
                        lastVisibleItem.offset + lastVisibleItem.size <= viewportHeight)
            }
        }
    }.value
}
Run Code Online (Sandbox Code Playgroud)

上面的代码不仅检查它是visibile item == last index列表中的最后一个,而且还检查它是否完全可见 ( lastVisibleItem.offset + lastVisibleItem.size <= viewportHeight)。

进而:

val state = rememberLazyListState()
var isAtBottom = state.isAtBottom()
LaunchedEffect(isAtBottom){
    if (isAtBottom) doSomething()
}

LazyColumn(
    state = state,
){
  //...
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我认为,根据其他答案,recyclerView.canScrollVertically(1)提到底部滚动的最佳解释是

fun LazyListState.isScrolledToTheEnd() : Boolean {
    val lastItem = layoutInfo.visibleItemsInfo.lastOrNull()
    return lastItem == null || lastItem.size + lastItem.offset <= layoutInfo.viewportEndOffset
}
Run Code Online (Sandbox Code Playgroud)