RecyclerView scrolled UP/DOWN listener

JavaAndroidAndroid RecyclerviewOnscrolllistener

Java Problem Overview


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

I tried with RecyclerView#OnScrollListener , it gives the amount of vertical scroll and the scroll state. How do we get the last scroll position when started to dragging and scrolled position when scroll state idle.

Java Solutions


Solution 1 - Java

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

Solution 2 - Java

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;

}

Solution 3 - Java

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

Solution 4 - Java

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.

Solution 5 - Java

this code work for me

private var nearmeListScrollListener = object : RecyclerView.OnScrollListener() {
        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)

          
                if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_SETTLING)
                    if (dy > 0) {
                        layout_vendros_list_header.hide()
                         layout_vendros_list_header.animate().translationY(1f)
                    } else if (dy < 0) {
                        layout_vendros_list_header.show()
                        layout_vendros_list_header.animate().translationY(0f)
                    }

        }
    }
    ```

Solution 6 - Java

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLibinView Question on Stackoverflow
Solution 1 - JavaReaz MurshedView Answer on Stackoverflow
Solution 2 - JavaXcihnegnView Answer on Stackoverflow
Solution 3 - JavaShahid SarwarView Answer on Stackoverflow
Solution 4 - JavasilvermouseView Answer on Stackoverflow
Solution 5 - JavaArash JahaniView Answer on Stackoverflow
Solution 6 - JavaAleksey TimoshchenkoView Answer on Stackoverflow