RecyclerView scrollToPosition不会触发scrollListener

我正在使用带有ScrollListener的RecyclerView:

mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // Do my logic } }); 

当我用手指滚动时,滚动侦听器触发了罚款。

但是当我逐步滚动时,就像那样:

 mRecyclerView.scrollToPosition(LAST_POSITION); 

滚动侦听器未被触发。

这是一个已知的问题。 这是因为RecyclerView不知道LayoutManager如何处理滚动或者它是否会处理滚动。

在下一个版本中,如果布局后的第一个或最后一个子位置发生更改(通常是调用滚动到位置的结果),您将收到对onScrolled的调用。

不幸的是,dx和dy将为0,因为RecyclerView并不真正知道布局管理器确实滚动了多少来处理scrollTo请求。 或者,您也可以使用ViewTreeObserver的滚动回调。

我遇到了同样的问题并find了一种解决方法,即在布局管理器中使用smoothScrollToPosition。 此方法触发滚动侦听器。 基本上这就是我用来拥有的东西:

 recyclerView.scrollToPosition(recyclerAdapter.getItemCount() - 1); 

现在我改为:

 recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null, recyclerAdapter.getItemCount() - 1); 

它对我来说很好。

这有点简陋,但你可以试试这个RecyclerView的子类:

 public class PatchedRecyclerView extends RecyclerView { private OnScrollListener listener; public PatchedRecyclerView(Context context) { super(context); } public PatchedRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public PatchedRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void setOnScrollListener(OnScrollListener listener) { super.setOnScrollListener(listener); this.listener = listener; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int preFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1; int preLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1; super.onLayout(changed, l, t, r, b); int postFirstChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(0)).getPosition() : -1; int postLastChildPosition = getChildCount() != 0 ? getChildViewHolder(getChildAt(getChildCount() - 1)).getPosition() : -1; // TODO: Insert proper DX and DY values if (preFirstChildPosition != postFirstChildPosition || preLastChildPosition != postLastChildPosition) listener.onScrolled(this, 0, 0); } } 
 int mFirst=0, mLast=0; recyclerview.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager(); mLast = llm.findLastCompletelyVisibleItemPosition(); mFirst = llm.findFirstCompletelyVisibleItemPosition(); } }); imgRight.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager(); llm.scrollToPositionWithOffset(mLast + 1, List.length()); } }); imgLeft.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { LinearLayoutManager llm = (LinearLayoutManager) recyclerview.getLayoutManager(); llm.scrollToPositionWithOffset(mFirst - 1, List.length()); } }); 

要通过回收器视图显式触发onScrollListener,请使用:

 recyclerView.smoothScrollBy(x, y); //x is the horizontal displacement and y is vertical displacement. 

我无法使用smoothScrollToPosition(过去我们遇到了一些问题)并且取决于第一项的位置似乎不可靠,所以我最终使用了yigit的答案(它已经被释放),不幸的是它没有’总是工作(我不知道为什么)。

所以我最终使用了之前添加到RecyclerView的滚动侦听器,遗憾的是我无法find此解决方案的起源。
如果你需要一个常量的话,我认为你不应该使用这个监听器,幸运的是我只需要在特定时间听。

覆盖RecyclerView:

 public class MyRecyclerView extends RecyclerView { public interface OnScrollStoppedListener{ void onScrollStopped(); } private static final int NEW_CHECK_INTERVAL = 100; private OnScrollStoppedListener mOnScrollStoppedListener; private Runnable mScrollerTask; private int mInitialPosition; public MyRecyclerView(Context context) { super(context); init(); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mScrollerTask = new Runnable() { public void run() { int newPosition = getScrollY(); if(mInitialPosition - newPosition == 0) {//has stopped if(mOnScrollStoppedListener !=null) { mOnScrollStoppedListener.onScrollStopped(); } } else { startScrollerTask(); } } }; } public void setOnScrollStoppedListener(MyRecyclerView.OnScrollStoppedListener listener){ mOnScrollStoppedListener = listener; } public void startScrollerTask() { mInitialPosition = getScrollY(); postDelayed(mScrollerTask, NEW_CHECK_INTERVAL); } } 

用法:

 myRecyclerView.setOnScrollStoppedListener(new MyRecyclerView.OnScrollStoppedListener() { @Override public void onScrollStopped() { // Do your thing } }); myRecyclerView.startScrollerTask(); 

请试试

 LinearLayoutManager.scrollToPositionWithOffset(int, int). 

LayoutManager.scrollToPosition()可能无法正常工作,但LinearLayoutManager.scrollToPositionWithOffset()可以正常工作。 和类似的GridLayoutManager一样。

或者我们必须编写自定义的实现方式,因为RecyclerView不知道LayoutManager如何滚动视图。

  class CustomLayoutManager extends LinearLayoutManager{ public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, final int position) { LinearSmoothScroller smoothScroller = new LinearSmoothScroller(mContext) { //Override the methods and write your implementation as per your requirement //one which controls the direction and another one calculate the speed per Pixel } } 

有时这就是诀窍

  new Handler().postDelayed(new Runnable() { @Override public void run() { yourList.scrollToPosition(position); } }, 200); 

Muito法律seu conselho。

  Button maisOpcoes = (Button) findViewById(R.id.maisOpcoes); maisOpcoes.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView, null , recyclerViewTmd.getItemCount() - 1); maisOpcoes.setVisibility(View.GONE); } });