RecyclerView scrollToPosition not trigger scrollLi

2020-05-18 11:07发布

I'm using RecyclerView, with 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
        }
 });

When I scroll with the finger, the scroll listener triggered fine.

But when I scroll progrematically, like that:

mRecyclerView.scrollToPosition(LAST_POSITION);

The scroll listener is not triggered.

8条回答
乱世女痞
2楼-- · 2020-05-18 11:41

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);
            }
        });
查看更多
闹够了就滚
3楼-- · 2020-05-18 11:41

To explicitly trigger onScrollListener over recycler view use:

recyclerView.smoothScrollBy(x, y);
//x is the horizontal displacement and y is vertical displacement.
查看更多
Anthone
4楼-- · 2020-05-18 11:42

This is a known issue. It is caused by the fact that RecyclerView does not know how LayoutManager will handle the scroll or if it will handle it at all.

In the next release, you'll receive a call to onScrolled if first and or last child position changes after a layout (which is generally the result of calling scroll to position).

Unfortunately, dx and dy will be 0 because RecyclerView does not really know how much layout manager did scroll to handle scrollTo request. Alternatively, you can also use the the ViewTreeObserver's scroll callback.

查看更多
女痞
5楼-- · 2020-05-18 11:50

I could not use the smoothScrollToPosition (we had some problems with it in the past) and depending on the position of the first item seemed unreliable, so I ended up using yigit's answer (it has been released already), unfortunately it didn't always work (I am not sure why).

So I ended up using a scroll listener I've added previously to the RecyclerView, sadly I cannot find the origin of this solution.
I don't think you should use this listener if you need a constant one, luckily I need to listen only at specific times.

Override the 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);
    }

}  

Usage:

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

myRecyclerView.startScrollerTask();
查看更多
The star\"
6楼-- · 2020-05-18 11:51

It's a bit rudimentary, but you could try this Subclass of 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);
    }
}
查看更多
Emotional °昔
7楼-- · 2020-05-18 11:52

I've faced the same issue and found a workaround, which is to use the smoothScrollToPosition in layout manager. This method triggers the scroll listener. So basically this is what I use to have:

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

and now I've changed to this:

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

and it's working fine for me.

查看更多
登录 后发表回答