繁体   English   中英

Jetpack Compose:LazyRow onScrollListener

[英]Jetpack Compose: LazyRow onScrollListener

我想知道是否有一种方法或资源可以参考,以便在滚动项目时对LazyRow产生副作用? 副作用基本上是在 viewModel 中调用 function 来更改列表 state 的 state。

  • 仅当当前 firstVisibleItemIndex 之后才应执行副作用
  • 滚动与以前不同不应执行副作用该项目未完全滚动我正在实现具有快速行为的全屏LazyRow项目

到目前为止,我已经尝试过NestedScrollConnection

class OnMoodItemScrolled : NestedScrollConnection {
    override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
        viewModel.fetchItems()
        return super.onPostFling(consumed, available)
    }
}

上面的问题是无论如何都会执行副作用 - 即使滚动后显示的项目与滚动前相同。

我还尝试按以下方式收集 listState 交互

val firstVisibleItem: Int = remember { sectionItemListState.firstVisibleItemIndex }
    sectionItemListState.interactionSource.collectIsDraggedAsState().let {
        if (firstVisibleItem != sectionItemListState.firstVisibleItemIndex) {
            viewModel.fetchItems()
        }
    }

上面的问题是副作用将在可组合项第一次组合时执行。

您可以使用LazyListState#firstVisibleItemIndex获取有关第一个可见项目的信息并存储此值。 当值更改时,项目将向上滚动。

就像是:

@Composable
private fun LazyListState.itemIndexScrolledUp(): Int {
    var previousIndex by remember(this) { mutableStateOf(firstVisibleItemIndex) }
    return remember(this) {
        derivedStateOf {
            if (firstVisibleItemIndex > previousIndex) {
                //scrolling up
                previousIndex
            } else {
                - 1
            }.also {
                //Update the previous index
                previousIndex = firstVisibleItemIndex
            }
        }
    }.value
}

接着:

val state = rememberLazyListState()
var index = state.itemIndexScrolledUp()

DisposableEffect(index){

     if (index != -1) {
          //...item is scrolled up
     }

      onDispose {  }   
}


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

我使用带有 2 个键的LaunchedEffect解决了我的问题。

val sectionItemListState = rememberLazyListState()
val flingBehavior = rememberSnapFlingBehavior(sectionItemListState)
var previousVisibleItemIndex by rememberSaveable {
    mutableStateOf(0)
}
val currentVisibleItemIndex: Int by remember {
    derivedStateOf { sectionItemListState.firstVisibleItemIndex }
}
val currentVisibleItemScrollOffset: Int by remember {
    derivedStateOf { sectionItemListState.firstVisibleItemScrollOffset }
}

LaunchedEffect(currentVisibleItemIndex, currentVisibleItemScrollOffset) {
    if (previousVisibleItemIndex != currentVisibleItemIndex && currentVisibleItemScrollOffset == 0) {
        // The currentVisible item is different than the previous one && it's fully visible
        viewModel.fetchItems()
        previousVisibleItemIndex = currentVisibleItemIndex
    }
}

使用currentVisibleItemIndexcurrentVisibleItemScrollOffset作为键将确保只要其中一个发生变化就会触发LaunchedEffect 此外,检查previousVisibleItemIndex是否不同于currentVisibleItemIndex将确保我们仅在可见项目发生变化时才触发此效果。 但是,如果使用已部分滚动,则此条件将为真,因为我有捕捉效果,它将 go 返回到之前的 position。这将导致两次触发效果。 为了确保我们仅在实际滚动到下一个/上一个完全可见的 position 时才触发效果,我们需要依赖scrollOffset

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM