30

How to check if a RecyclerView is scrollable, ie, there are items below/above the visible area

I have a dropdown in my recycler view which works by using notifyItemRangeInserted() and notifyItemRangeRemoved(). Whenever any of this happens, I want to check if the RecyclerView is scrollable or not, as I have to adjust another view, a banner like in newsstand, accordingly

Sourabh
  • 8,243
  • 10
  • 52
  • 98

10 Answers10

43

What about

// 1 = down; -1 = up
recyclerView.canScrollVertically(-1)

If you want to check if there is any scrollable space, no matter which direction

cardList.canScrollVertically(1) || cardList.canScrollVertically(-1)
Tyler
  • 19,113
  • 19
  • 94
  • 151
Simas
  • 43,548
  • 10
  • 88
  • 116
  • 2
    This should be the accepted answer, the current answer does not work with `GridLayoutManager`. `findLastCompletelyVisibleItemPosition()` always returns `-1` (`RecyclerView.NO_POSITION`). – olfek Jun 22 '18 at 13:14
  • 10
    This should be the accepted answer, BUT (!) DO NOT PASS '0' as a parameter! It must be negative of positive int. If you want to check if there is any scrollable space, no matter which direction - use `(cardList.canScrollVertically(1) || cardList.canScrollVertically(-1)` – Kirill Karmazin Aug 29 '18 at 11:33
  • Great help. Thanks. – Syed Arsalan Kazmi Aug 11 '21 at 15:42
  • 1
    recyclerView.canScrollVertically(1) || recyclerView.canScrollVertically(-1) always returns false, so what to do for that? – Karan Mehta Apr 22 '22 at 05:45
28

There you go:

public boolean isRecyclerScrollable() {
  LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
  RecyclerView.Adapter adapter = recyclerView.getAdapter();
  if (layoutManager == null || adapter == null) return false;

  return layoutManager.findLastCompletelyVisibleItemPosition() < adapter.getItemCount() - 1;
}
Simas
  • 43,548
  • 10
  • 88
  • 116
  • Is there also a way to detect the amount by which it is scrollable? Assuming all items are not of same size – Sourabh Sep 23 '15 at 19:17
  • @Sourabh without quietly loading all the item views and measuring them in the background - I doubt it. – Simas Sep 23 '15 at 19:21
  • 2
    the name of this method is misleading. It actually indicates whether you can scroll down or not from the current position. That means that it will return 'false' even if there is a lot of items above your current position and you can scroll up a couple of screens. – Kirill Karmazin Aug 29 '18 at 11:20
  • It will return `false` when called if you see the last item in the RecyclerView. – Oleksandr Nos Jan 28 '19 at 16:11
23

I found an easy solution that works regardless of the position you are in the list:

public boolean isRecyclerScrollable(RecyclerView recyclerView) {
    return recyclerView.computeHorizontalScrollRange() > recyclerView.getWidth() || recyclerView.computeVerticalScrollRange() > recyclerView.getHeight();
}
Fabio Picchi
  • 1,202
  • 2
  • 10
  • 22
  • 1
    This will work, tested. But the best approach is in Simas's answer (note: don't use 0 as a parameter, use -1 or 1 instead) – Kirill Karmazin Aug 29 '18 at 11:36
  • Great! I can't remember if Simas's approach was available when I gave my answer (some APIs in the Android SDK are very convoluted D:). Thanks for the tip! – Fabio Picchi Aug 30 '18 at 12:45
  • 1
    Both methods work fine but I prefer this one because of less code. – Jeffrey Nov 02 '18 at 02:51
  • This worked the best for me. Note however that the scrollRange does not respect paddings. If you have a padding in the RecyclerView set, this method may indicate that the view is not scrolling although it actually is. I'll post an answer with the complete code I'm using. – Phocacius Feb 12 '19 at 14:49
3

The idea is to check if the last completely visible element is the last element in the list.

private boolean isScrollable()
{
    return mLinearLayoutManager.findLastCompletelyVisibleItemPosition() + 1 ==
        mRecyclerViewAdapter.getItemCount();
}
Mahdi Astanei
  • 1,905
  • 1
  • 17
  • 30
Sotti
  • 14,089
  • 2
  • 50
  • 43
3

This one works for me.

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);


            boolean isRecylerScrollable = recyclerView.computeHorizontalScrollRange() > recyclerView.getWidth();

            if(isRecylerScrollable){
             //do something
            }
    });
}
shinta
  • 189
  • 2
  • 16
2

I had the same problem and the answers already posted, especially Fabios, brought me on the right track. The scrollRange does not support paddings though, so they need to taken into account as well if your Recyclerview has a padding.

I'm using the following extension property in Kotlin now to determine whether or not the view is scrolling.

/**
 * computes whether the RecyclerView's content is larger than the view container, i.e. whether or not the user can scroll
 * returns null if either layout manager or adapter is not yet set or an incompatible layout manager is used (Linear- & GridLayoutManager work)
 */
val RecyclerView.canScroll: Boolean?
    get() {
        // if there's no adapter set, we don't know yet whether or not the view is scrollable
        if (adapter == null) return null
        val manager = layoutManager as? LinearLayoutManager ?: return null
        if (manager.orientation == RecyclerView.HORIZONTAL) {
            return computeHorizontalScrollRange() + paddingLeft + paddingRight > width
        }
        return computeVerticalScrollRange() + paddingTop + paddingBottom > height
    }
Phocacius
  • 1,127
  • 1
  • 13
  • 23
1

In Kotlin you can do :

 fun isRecyclerScrollable(): Boolean {
    val layoutManager = recyclerView.layoutManager as LinearLayoutManager
    val adapter = recyclerView.adapter
    return if (adapter == null) false else layoutManager.findLastCompletelyVisibleItemPosition() < adapter.itemCount - 1
}
Jéwôm'
  • 3,753
  • 5
  • 40
  • 73
0
boolean isScrollable() {
    LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
    int itemCount = mRecyclerView.getAdapter().getItemCount();

    return !(itemCount == 0 ||
    (layoutManager.findFirstCompletelyVisibleItemPosition() == 0 &&
    layoutManager.findLastCompletelyVisibleItemPosition() == itemCount - 1));
}
DmitryArc
  • 4,757
  • 2
  • 37
  • 42
0

Use this approach:

recyclerView.viewTreeObserver.addOnScrollChangedListener {
    val canScrollUp = recyclerView.canScrollVertically(-1)
    val canScrollDown = recyclerView.canScrollVertically(1)
}
Dario Brux
  • 1,871
  • 1
  • 17
  • 15
0
  1. First create a boolean for check the loop.
  2. Add onScrolled Listener:
binding.rvInformation.addOnScrollListener(object : RecyclerView.OnScrollListener() {
           override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
               super.onScrolled(recyclerView, dx, dy)
               if (!scrollChecked) { // <- check the 1 loop
                   scrollChecked = true
                   if (binding.rvInformation.canScrollVertically(1)) {
                       // Can scroll
                   } else {
                       // Can't scroll
                   }
               }

           }
       })
DavidUps
  • 366
  • 3
  • 9