【问题标题】:Scroll an Android RecyclerView and control the exact location on screen滚动 Android RecyclerView 并控制屏幕上的确切位置
【发布时间】:2020-04-08 13:53:28
【问题描述】:

我正在寻找一种以编程方式缓慢滚动 RecyclerView 以便将某个元素 targetPosition 准确地放在屏幕中间的方法。请注意,我在 RecylerView 中的所有项目在设计上都具有相同的高度。 RecyclerView 是垂直的。我正在使用 Kotlin 和 AndroidX 编程

我试过了:

smoothScrollToPosition(targetPosition)

它滚动很慢(我也可以通过扩展 LinearLayoutManager 和覆盖 calculateSpeedPerPixel() 来控制速度 - 请参阅 How can i control the scrolling speed of recyclerView.smoothScrollToPosition(position)),但是我无法控制滚动后列表项在屏幕上的确切位置.我只知道它将在屏幕上完全可见。

我试过了:

scrollToX(0, targetPosition * itemHeight - screenHeight / 2)

它给了我错误消息:“W/RecyclerView:RecyclerView 不支持滚动到绝对位置。请改用 scrollToPosition”

我还尝试将 RecyclerView 替换为包含所有子项的 LinearLayoutManager,并在视图中翻译 LinearLayoutManager,但最初我没有让子项在屏幕之外进行绘制。

这个问题有解决办法吗?

【问题讨论】:

  • 你试过scrollToPosition(0)吗?
  • 是的。也许我不清楚,我有一个比方说 100 个项目的 RecyclerView,我想滚动直到我说项目 50 正好在屏幕中间。

标签: android kotlin android-recyclerview scroll androidx


【解决方案1】:

你可以根据你的实际目标位置和可见物品的数量来计算smoothScrollToPosition的targetPosition。

关于如何做到这一点的快速 POC:

  val scrollToPosition = 50

  val layoutManager = recyclerView.layoutManager as LinearLayoutManager
  val firstPosition = layoutManager.findFirstVisibleItemPosition()
  val lastPosition = layoutManager.findLastVisibleItemPosition()
  val visibleItems =  lastPosition - firstPosition + 1

  if (firstPosition < scrollToPosition) {
      recyclerView.smoothScrollToPosition(scrollToPosition + (visibleItems / 2))
  } else {
      recyclerView.smoothScrollToPosition(scrollToPosition - (visibleItems / 2))
  }

如果您想要更精确的结果,即项目应该正好在屏幕的中间,您可以使用项目的高度(因为它是固定的)和 RecyclerView 的高度,然后计算要滚动的偏移量。并调用:

recyclerView.scrollBy(dx, dy)

或者:

recyclerView.smoothScrollBy(dx, dy)

【讨论】:

    【解决方案2】:

    谢谢@Bob。我错过了 scrollBy()。按照您的建议,这是对我有用的代码。

    class RecyclerViewFixedItemSize : RecyclerView {
        var itemFixedSize : Int = 0
    
        constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
        }
    
        constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        }
    
        constructor(context: Context) : super(context) {
        }
    
        fun smoothScrollToPositionCentered(position: Int) {
            // Find the fixed item size - once for all
            if (itemFixedSize == 0) {
                val ll = layoutManager as LinearLayoutManager
                val fp = ll.findFirstCompletelyVisibleItemPosition()
                val fv = ll.getChildAt(fp)
                itemFixedSize = fv!!.height
            }
    
            // find the recycler view position and screen coordinates of the first item (partially) visible on screen
            val ll = layoutManager as LinearLayoutManagerFixedItemSize
            val fp = ll.findFirstVisibleItemPosition()
            val fv = ll.getChildAt(0)
    
            // find the middle of the recycler view
            val dyrv = (top - bottom ) / 2
    
            // compute the number of pixels to scroll to get the view position in the center
            val dy = (position - fp) * itemFixedSize + dyrv + fv!!.top + itemFixedSize / 2
    
            smoothScrollBy(0, dy)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-08
      • 2021-08-13
      • 2021-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多