【问题标题】:Jetpack Compose LazyColumn programmatically scroll to ItemJetpack Compose LazyColumn 以编程方式滚动到项目
【发布时间】:2021-03-11 21:16:01
【问题描述】:

有没有办法以编程方式将LazyColumn 滚动到列表中的某个项目?我认为可以通过提升LazyColumn 参数state: LazyListState = rememberLazyListState() 来完成,但我不知道如何改变这种状态,例如点击按钮。

【问题讨论】:

    标签: android kotlin android-jetpack-compose android-jetpack-compose-list


    【解决方案1】:

    1.0.x LazyListState支持滚动位置通过

    类似:

    val listState = rememberLazyListState()
    // Remember a CoroutineScope to be able to launch
    val coroutineScope = rememberCoroutineScope()
    
    LazyColumn(state = listState) {
        // ...
    }
    
    Button (
        onClick = { 
            coroutineScope.launch {
                // Animate scroll to the 10th item
                listState.animateScrollToItem(index = 10)
            }
        }
    ){
        Text("Click")
    }
    
      
    

    【讨论】:

      【解决方案2】:

      在 Compose 1.0.0-alpha07 中,没有公共 API,但有一些内部 API 到 LazyListState#snapToItemIndex

      /**
       * Instantly brings the item at [index] to the top of the viewport, offset by [scrollOffset]
       * pixels.
       *
       * Cancels the currently running scroll, if any, and suspends until the cancellation is
       * complete.
       *
       * @param index the data index to snap to
       * @param scrollOffset the number of pixels past the start of the item to snap to
       */
      @OptIn(ExperimentalFoundationApi::class)
      suspend fun snapToItemIndex(
          @IntRange(from = 0)
          index: Int,
          @IntRange(from = 0)
          scrollOffset: Int = 0
      ) = scrollableController.scroll {
          scrollPosition.update(
              index = DataIndex(index),
              scrollOffset = scrollOffset,
              // `true` will be replaced with the real value during the forceRemeasure() execution
              canScrollForward = true
          )
          remeasurement.forceRemeasure()
      }
      

      也许在即将发布的版本中,我们可以看到更新。

      【讨论】:

        【解决方案3】:

        这是我制作粘性标题、列表和滚动的代码

        @ExperimentalFoundationApi
        @Composable
        private fun ListView(data: YourClass) { 
        
        //this is to remember state, internal API also use the same
            val state = rememberLazyListState()
        
            LazyColumn(Modifier.fillMaxSize(), state) {
                itemsIndexed(items = data.list, itemContent = { index, dataItem ->
                    ItemView(dataItem)// your row
                })
               // header after some data, according to your condition
                    stickyHeader {
                        ItemDecoration()// compose fun for sticky header 
                    }
        // More items after header
                    itemsIndexed(items = data.list2, itemContent = { index, dataItem ->
                    ItemView(dataItem)// your row
                })
                }
        
               // scroll to top
              // I am scrolling to top every time data changes, use accordingly
                CoroutineScope(Dispatchers.Main).launch {
                    state.snapToItemIndex(0, 0)
                }
            }
        }
        

        【讨论】:

          【解决方案4】:

          试试

          lazyListState.animateScrollToItem(lazyListState.firstVisibleItemIndex)
          
          
          @Composable
          fun CircularScrollList(
              value: Long,
              onValueChange: () -> Unit = {}
          ) {
              val lazyListState = rememberLazyListState()
              val scope = rememberCoroutineScope()
          
              val items = CircularAdapter(listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
              scope.launch { lazyListState.scrollToItem(items.midIndex()) }
          
              LazyColumn(
                  modifier = Modifier
                      .requiredHeight(height = 120.dp)
                      .border(width = 1.dp, color = Color.Black),
                  state = lazyListState,
              ) {
                  items(items) {
                      if (!lazyListState.isScrollInProgress) {
                          scope.launch {
                              lazyListState.animateScrollToItem(lazyListState.firstVisibleItemIndex)
                          }
                      }
                      Text(
                          text = "$it",
                          modifier = Modifier.requiredHeight(40.dp),
                          style = TextStyle(fontSize = 30.sp)
                      )
                  }
              }
          }
          
          class CircularAdapter(
              private val content: List<Int>
          ) : List<Int> {
              fun midIndex(): Int = Int.MAX_VALUE / 2 + 6
              override val size: Int = Int.MAX_VALUE
              override fun contains(element: Int): Boolean = content.contains(element = element)
              override fun containsAll(elements: Collection<Int>): Boolean = content.containsAll(elements)
              override fun get(index: Int): Int = content[index % content.size]
              override fun indexOf(element: Int): Int = content.indexOf(element)
              override fun isEmpty(): Boolean = content.isEmpty()
              override fun iterator(): Iterator<Int> = content.iterator()
              override fun lastIndexOf(element: Int): Int = content.lastIndexOf(element)
              override fun listIterator(): ListIterator<Int> = content.listIterator()
              override fun listIterator(index: Int): ListIterator<Int> = content.listIterator(index)
              override fun subList(fromIndex: Int, toIndex: Int): List<Int> =
                  content.subList(fromIndex, toIndex)
          }
          

          【讨论】:

            【解决方案5】:

            我已经解决了两种方法

            一种方式:我选择了这种最好的方式

            LaunchedEffect(true) {
              repeat(Int.MAX_VALUE) {
                  delay(TIME_DELAY_BANNER)
                  pagerState.animateScrollToPage(page = it % pagerState.pageCount)
              }
            }
            

            两种方式:

            var index = pagerState.currentPage
            LaunchedEffect(true) {
                        while (true) {
                            delay(TIME_DELAY_BANNER)
                            if (index == pagerState.pageCount) {
                                index = 0
                            }
                  pagerState.animateScrollToPage(page = index++)
              }
            }
            

            【讨论】:

              猜你喜欢
              • 2021-08-13
              • 2022-09-29
              • 2021-09-28
              • 1970-01-01
              • 1970-01-01
              • 2021-11-30
              • 1970-01-01
              • 2022-10-04
              • 2021-11-26
              相关资源
              最近更新 更多