簡體   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