如何使用RecyclerView.scrollToPosition()将位置移动到当前视图的顶部?

57
RecyclerView.scrollToPosition()在使用时非常奇怪。
例如,假设有一个名为"rv"RecyclerView
  1. 如果当前视图下显示第10个项目,调用rv.scrollToPosition(10)RecyclerView将滚动到第10个位置并显示在底部。
  2. 如果第10个项目已经在当前RecyclerView中,调用rv.scrollToPosition(10),不会有滚动和其他反应。
  3. 如果第10个项目位于当前RecyclerView顶部,调用rv.scrollToPosition(10)RecyclerView将滚动到第10个位置并显示在顶部。
为便于理解,请参考此图片enter image description here
然而,我需要的是,无论何时调用它,RecyclerView都将像第3种情况一样滚动到所需位置的视图顶部。该如何实现呢?

4
https://dev59.com/f18d5IYBdhLWcg3wYxc- - USKMobility
1
这正是我想要的!非常感谢!嗯...我想我应该删除我的问题... - cryyyyy
1
使用linearLayoutManager.scrollToPositionWithOffset(2, 20)方法; 参见滚动RecyclerView以将选定项显示在顶部 - Fan Applelin
https://dev59.com/f18d5IYBdhLWcg3wYxc- - razi
我在这个问题上点了+1,因为它的表述方式很好,能够清晰地解释问题。 - Gaurav Bansal
5个回答

66

如果我理解问题正确,您想要滚动到特定的位置,但该位置是适配器的位置而不是RecyclerView的项目位置。

您只能通过LayoutManager实现此目的。

可以像这样执行操作:

rv.getLayoutManager().scrollToPosition(youPositionInTheAdapter).

我该如何将适配器位置(AdapterPosition)传递给这个方法? - Bot
17
我确定这是错误的。在RecyclerView上调用scrollToPosition方法只会调用LayoutManager上的同名方法。甚至在javadoc中也指出:“RecyclerView不实现滚动逻辑,而是将调用转发到android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition方法。”在RecyclerView或LayoutManager上调用scrollToPosition方法具有完全相同的效果。 - Graydyn Young
@Zeeshan的答案使用了StaggeredGridLayoutManager非常有效!(见下文) - Abigail La'Fay
2
使用linearLayoutManager.scrollToPositionWithOffset(position, 0); - Castor
2
@Castor感谢您的回复。这是一项看似微不足道但却至关重要的区别 - scrollToPosition 看起来可以确保目标视图在 Recycler 中可见(通常是底部),而 scrollToPositionWithOffset 的偏移量为0 可以确保目标视图在 Recycler 顶部可见。 - rmirabelle

28

以下链接可能解决您的问题:

https://dev59.com/310Z5IYBdhLWcg3wpRhW#43505830

只需创建一个 SmoothScroller,然后使用 SNAP_TO_START 选项即可:

RecyclerView.SmoothScroller smoothScroller = new 
LinearSmoothScroller(context) {
   @Override protected int getVerticalSnapPreference() {
       return LinearSmoothScroller.SNAP_TO_START;
   }
};

现在您可以设置想要滚动到的位置:

smoothScroller.setTargetPosition(position);

将SmoothScroller传递给LayoutManager:

layoutManager.startSmoothScroll(smoothScroller);

4
如果您想进行平滑滚动,那没问题,但如果您想进行自动滚动怎么办? - 4gus71n
如果您想要自动滚动到某个位置,那么这段代码将完美地实现。它将以平滑的过渡自动滚动到某个位置...我希望我理解了您的问题。 - Ritesh
4
问题在于我的RecyclerView有大约700个项目,所以如果离目标滚动的距离<30,则我使用平稳滚动,这段代码完美地运作。但是如果离目标滚动的距离>30,我想要自动跳转到该项目。在这种情况下,我不想使用平稳滚动。如何将视图"捕捉到"该项的开头? - 4gus71n
1
@4gus71n 我有同样的问题。我相信你想要改变动作来使用jumpTo()。以前有一个瞬间滚动条,但在api 22中已被弃用。 - Alexander N.
2
@AlexanderN。很好,我不知道那个方法。马上去试试。 - 4gus71n
@Luke 我做了类似的事情,但是我遇到了这个错误 java.lang.NullPointerException:尝试从空对象引用上读取字段'androidx.recyclerview.widget.RecyclerView$ViewFlinger androidx.recyclerview.widget.RecyclerView.mViewFlinger' at androidx.recyclerview.widget.RecyclerView$SmoothScroller.start(RecyclerView.java:11795) at androidx.recyclerview.widget.RecyclerView$LayoutManager.startSmoothScroll(RecyclerView.java:8470) - Abhishek

5

这是Kotlin代码片段,但你只需要了解如何正确按位置滚动到该项。关键是声明布局管理器的成员变量并使用其方法进行滚动。

lateinit var layoutManager: LinearLayoutManager

fun setupView() {
    ...

    layoutManager = LinearLayoutManager(applicationContext)
    mainRecyclerView.layoutManager = layoutManager

    ...
}

fun moveToPosition(position: Int) {
    layoutManager.scrollToPositionWithOffset(position, 0)
}

4

如果您想滚动到特定位置,并且该位置是适配器的位置,则可以使用StaggeredGridLayoutManagerscrollToPosition函数。

   StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
   staggeredGridLayoutManager.scrollToPosition(10);
   recyclerView.setLayoutManager(staggeredGridLayoutManager);

0

在这里尝试使用 recycler_view.smoothScrollBy(0, 100);,其中0代表x坐标100代表y坐标。我在垂直的recyclerView中使用它,想要滚动到垂直列表中的下一个位置,如果要回到上一个位置,只需将100替换为-100


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接