我正在寻找一种方法来滚动RecyclerView,以显示选中的项目在顶部。

在一个ListView中,我能够通过使用scrollTo(x,y)来做到这一点,并获得需要居中的元素的顶部。

喜欢的东西:

@Override
public void onItemClick(View v, int pos){
    mylistView.scrollTo(0, v.getTop());
}

问题是RecyclerView在使用它的scrollTo方法时返回一个错误说

RecyclerView不支持滚动到绝对位置

我如何滚动一个RecyclerView把选定的项目放在视图的顶部?


当前回答

如果你正在使用LinearLayoutManager或交错的GridLayoutManager,它们都有一个scrollToPositionWithOffset方法,该方法既取位置,也取项目从RecyclerView开始的偏移量,这似乎可以完成你所需要的(将偏移量设置为0应该与顶部对齐)。

例如:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);

其他回答

我使用下面的代码将一个项目(thisView)平滑滚动到顶部。 它也适用于GridLayoutManager不同高度的视图:

View firstView = mRecyclerView.getChildAt(0);
int toY = firstView.getTop();
int firstPosition = mRecyclerView.getChildAdapterPosition(firstView);
View thisView = mRecyclerView.getChildAt(thisPosition - firstPosition);
int fromY = thisView.getTop();

mRecyclerView.smoothScrollBy(0, fromY - toY);

似乎能快速解决问题。

如果你正在使用LinearLayoutManager或交错的GridLayoutManager,它们都有一个scrollToPositionWithOffset方法,该方法既取位置,也取项目从RecyclerView开始的偏移量,这似乎可以完成你所需要的(将偏移量设置为0应该与顶部对齐)。

例如:

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);

在我的情况下,我的RecyclerView有一个填充顶部像这样

<android.support.v7.widget.RecyclerView
     ...
     android:paddingTop="100dp"
     android:clipToPadding="false"
/>

然后滚动一个项目到顶部,我需要

recyclerViewLinearLayoutManager.scrollToPositionWithOffset(position, -yourRecyclerView.getPaddingTop());

请注意,如果scrolltopposition不工作,请注意您的RecyclerView是在一个NestedScrollView;参考这篇文章

我可以在这里添加的是如何使它与DiffUtil和ListAdapter一起工作

你可能会注意到调用recyclerView. scrolltopposition (pos)或(recyclerView. scrolltopposition)。layoutManager作为LinearLayoutManager)。如果在adapter.submitList后直接调用scrollToPositionWithOffset(pos, offset)将不起作用。这是因为differ在后台线程中查找更改,然后异步地将更改通知适配器。在一个SO上,我看到了几个错误的答案和不必要的延迟等来解决这个问题。

为了正确地处理这种情况,submitList有一个回调函数,在应用更改时调用它。

因此,在这种情况下,正确的kotlin实现是:

//memorise target item here and a scroll offset if needed
adapter.submitList(items) { 
    val pos = /* here you may find a new position of the item or just use just a static position. It depends on your case */
    recyclerView.scrollToPosition(pos) 
}
//or
adapter.submitList(items) { recyclerView.smoothScrollToPosition(pos) }
//or etc
adapter.submitList(items) { (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(pos, offset) }