RecyclerView scrollToPosition不会触发scrollListener

时间:2015-01-07 12:26:27

标签: android android-recyclerview onscrolllistener

我正在使用RecyclerView,ScrollListener:

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);

不会触发滚动侦听器。

8 个答案:

答案 0 :(得分:23)

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

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

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

答案 1 :(得分:23)

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

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

现在我改为:

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

它对我来说很好。

答案 2 :(得分:0)

它有点简陋,但你可以试试这个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);
    }
}

答案 3 :(得分:0)

Muito legal 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);
            }
        });

答案 4 :(得分: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());
    }
});

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

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

覆盖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();

答案 7 :(得分:0)

请尝试

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);