RecyclerView scrolled UP/DOWN listener

前端 未结 5 474
无人共我
无人共我 2020-11-29 01:32

How do we know if user scrolled down or up in RecyclerView ?

I tried with RecyclerView#OnScrollListener , it gives the amount of vertical s

相关标签:
5条回答
  • 2020-11-29 01:46

    There is my implementation of CustomRecyclerView with all type of scroll listeners

    public class CustomRecyclerView extends RecyclerView
    {
    private boolean mIsScrolling;
    private boolean mIsTouching;
    private OnScrollListener mOnScrollListener;
    private Runnable mScrollingRunnable;
    private int y = 0;
    
    public abstract static class OnScrollListener
    {
        void onScrollChanged(CustomRecyclerView RvView, int x, int y, int oldX, int oldY)
        {
            //if you need just override this method
        }
    
        void onEndScroll(CustomRecyclerView RvView)
        {
            //if you need just override this method
        }
    
        protected abstract void onGoUp();
    
        protected abstract void onGoDown();
    }
    
    public CustomRecyclerView(final Context context)
    {
        super(context);
    }
    
    public CustomRecyclerView(final Context context, @Nullable final AttributeSet attrs)
    {
        super(context, attrs);
    }
    
    public CustomRecyclerView(final Context context, @Nullable final AttributeSet attrs, final int defStyle)
    {
        super(context, attrs, defStyle);
    }
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent iEv)
    {
        if (isEnabled())
        {
            processEvent(iEv);
            super.dispatchTouchEvent(iEv);
            return true; //to keep receive event that follow down event
        }
    
        return super.dispatchTouchEvent(iEv);
    }
    
    private void processEvent(final MotionEvent iEv)
    {
        switch (iEv.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                y = (int) iEv.getY();
                break;
    
            case MotionEvent.ACTION_UP:
                y = (int) iEv.getY();
    
                if (mIsTouching && !mIsScrolling && mOnScrollListener != null)
                {
                    mOnScrollListener.onEndScroll(this);
                }
    
                mIsTouching = false;
                break;
            case MotionEvent.ACTION_MOVE:
                mIsTouching = true;
                mIsScrolling = true;
    
                int newY = (int) iEv.getY();
                int difY = y - newY;
    
                int MAX_VALUE = 200;
                int MIN_VALUE = -200;
                if (difY > MAX_VALUE)
                {
                    if (mOnScrollListener != null)
                    {
                        mOnScrollListener.onGoDown();
                    }
                    y = newY;
                }
                else if (difY < MIN_VALUE)
                {
                    if (mOnScrollListener != null)
                    {
                        mOnScrollListener.onGoUp();
                    }
                    y = newY;
                }
    
                break;
        }
    }
    
    @Override
    protected void onScrollChanged(int iX, int iY, int iOldX, int iOldY)
    {
        super.onScrollChanged(iX, iY, iOldX, iOldY);
    
        if (Math.abs(iOldX - iX) > 0)
        {
            if (mScrollingRunnable != null)
            {
                removeCallbacks(mScrollingRunnable);
            }
    
            mScrollingRunnable = () ->
            {
                if (mIsScrolling && !mIsTouching && mOnScrollListener != null)
                {
                    mOnScrollListener.onEndScroll(CustomRecyclerView.this);
                }
    
                mIsScrolling = false;
                mScrollingRunnable = null;
            };
    
            postDelayed(mScrollingRunnable, 200);
        }
    
        if (mOnScrollListener != null)
        {
            mOnScrollListener.onScrollChanged(this, iX, iY, iOldX, iOldY);
        }
    }
    
    public void scrollToView(final View iV)
    {
        // Get deepChild Offset
        Point childOffset = new Point();
        getDeepChildOffset(CustomRecyclerView.this, iV.getParent(), iV, childOffset);
        // Scroll to child.
    
        CustomRecyclerView.this.scrollToY(childOffset.y);
    }
    
    private void getDeepChildOffset(final ViewGroup mainParent, final ViewParent parent, final View child, final Point accumulatedOffset)
    {
        ViewGroup parentGroup = (ViewGroup) parent;
        accumulatedOffset.x += child.getLeft();
        accumulatedOffset.y += child.getTop();
        if (parentGroup.equals(mainParent))
        {
            return;
        }
        getDeepChildOffset(mainParent, parentGroup.getParent(), parentGroup, accumulatedOffset);
    }
    
    public void scrollToY(final int iY)
    {
        CustomRecyclerView.this.postDelayed(() ->
        {
            int x = 0;
            int y = iY;
            ObjectAnimator xTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollX", x);
            ObjectAnimator yTranslate = ObjectAnimator.ofInt(CustomRecyclerView.this, "scrollY", y);
    
            AnimatorSet animators = new AnimatorSet();
            animators.setDuration(500L);
            animators.playTogether(xTranslate, yTranslate);
            animators.addListener(new Animator.AnimatorListener()
            {
    
                @Override
                public void onAnimationStart(Animator arg0)
                {
                    // noting
                }
    
                @Override
                public void onAnimationRepeat(Animator arg0)
                {
                    // noting
                }
    
                @Override
                public void onAnimationEnd(Animator arg0)
                {
                    // noting
                }
    
                @Override
                public void onAnimationCancel(Animator arg0)
                {
                    // noting
                }
            });
            animators.start();
        }, 300);
    }
    
    public void scrollToTop()
    {
        scrollToY(0);
    }
    
    public void setOnRvScrollListener(OnScrollListener mOnEndScrollListener)
    {
        this.mOnScrollListener = mOnEndScrollListener;
    }
    }
    

    And there is sample of usage

    private void setRecyclerViewSettings()
    {
        mRv.setLayoutManager(new LinearLayoutManager(getActivity()));
        mRv.setOnRvScrollListener(mScrollListener);
    }
    
    private CustomRecyclerView.OnScrollListener mScrollListener = new CustomRecyclerView.OnScrollListener()
    {
        @Override
        protected void onGoUp()
        {
            AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
        }
    
        @Override
        protected void onGoDown()
        {
            AppUtils.hideKeyboard(getContext(), mRvDynamicFormQuestions.getFocusedChild());
        }
    };
    
    0 讨论(0)
  • 2020-11-29 01:48

    The accepted answer works fine, but @MaciejPigulski gave more clear and neat solution in the comment below. I just putting it as an answer here. Here's my working code.

    mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if (dy > 0) {
                // Scrolling up
            } else {
                // Scrolling down
            }
        }
    
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
    
            if (newState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
                // Do something
            } else if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                // Do something
            } else {
                // Do something
            }
        }
    });
    
    0 讨论(0)
  • 2020-11-29 01:58

    Try this way:

    private static int firstVisibleInListview;
    
    firstVisibleInListview = yourLayoutManager.findFirstVisibleItemPosition();
    

    In your scroll listener:

    public void onScrolled(RecyclerView recyclerView, int dx, int dy) 
    {
        super.onScrolled(recyclerView, dx, dy);
    
        int currentFirstVisible = yourLayoutManager.findFirstVisibleItemPosition();
    
        if(currentFirstVisible > firstVisibleInListview)
           Log.i("RecyclerView scrolled: ", "scroll up!");
        else
           Log.i("RecyclerView scrolled: ", "scroll down!");  
    
        firstVisibleInListview = currentFirstVisible;
    
    }
    
    0 讨论(0)
  • 2020-11-29 02:07

    I wanted to hide a layout if the recyclerview is scrolled down and then make it visible if the recyclerview is scrolled up. I did some thinking and came up with this logic. Variable y is a global static int. Do not forget to declare y as static int y;

    I hope it helps someone :)

     mRecyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(lLayout) {
               @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                // super.onScrolled(recyclerView, dx, dy);
                    y=dy;
                }
    
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    if(mRecyclerView.SCROLL_STATE_DRAGGING==newState){
                        //fragProductLl.setVisibility(View.GONE);
                    }
                    if(mRecyclerView.SCROLL_STATE_IDLE==newState){
                       // fragProductLl.setVisibility(View.VISIBLE);
                        if(y<=0){
                            fragProductLl.setVisibility(View.VISIBLE);
                        }
                        else{
                            y=0;
                            fragProductLl.setVisibility(View.GONE);
                        }
                    }
                }
            });
    
    0 讨论(0)
  • 2020-11-29 02:10

    Another simple solution that can detect scroll direction with the help of your adapter:

    class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
        int lastItemPosition = -1;
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            if (position > lastItemPosition) {
                // Scrolled Down
            }
            else {
                // Scrolled Up
            }
            lastItemPosition = position;
         }
    }
    

    ^ Helpful when doing item animations upon scrolling.

    PS: This will tell you directions discontinuously until further onBindViewHolder calls.

    0 讨论(0)
提交回复
热议问题