[android] How to disable RecyclerView scrolling?

I cannot disable scrolling in the RecyclerView. I tried calling rv.setEnabled(false) but I can still scroll.

How can I disable scrolling?

This question is related to android scroll android-recyclerview

The answer is


I know this already has an accepted answer, but the solution doesn't take into account a use-case that I came across.

I specifically needed a header item that was still clickable, yet disabled the scrolling mechanism of the RecyclerView. This can be accomplished with the following code:

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
                            @Override
     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
         return e.getAction() == MotionEvent.ACTION_MOVE;
     }

     @Override
     public void onTouchEvent(RecyclerView rv, MotionEvent e) {

     }

     @Override
     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
});

Extend the LayoutManager and override canScrollHorizontally()and canScrollVertically() to disable scrolling.

Be aware that inserting items at the beginning will not automatically scroll back to the beginning, to get around this do something like:

  private void clampRecyclerViewScroll(final RecyclerView recyclerView)
  {
    recyclerView.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver()
    {
      @Override
      public void onItemRangeInserted(int positionStart, int itemCount)
      {
        super.onItemRangeInserted(positionStart, itemCount);
        // maintain scroll position at top
        if (positionStart == 0)
        {
          RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
          if (layoutManager instanceof GridLayoutManager)
          {
            ((GridLayoutManager) layoutManager).scrollToPositionWithOffset(0, 0);
          }else if(layoutManager instanceof LinearLayoutManager)
          {
            ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(0, 0);
          }
        }
      }
    });
  }

For stop scrolling by touch but keep scrolling via commands :

if (appTopBarMessagesRV == null) { appTopBarMessagesRV = findViewById(R.id.mainBarScrollMessagesRV);

        appTopBarMessagesRV.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {

                if ( rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING)
                {
                     // Stop  scrolling by touch

                    return false;
                }
                return  true;
            }
        });
    }

Add

android:descendantFocusability="blocksDescendants"

in your child of SrollView or NestedScrollView (and parent of ListView, recyclerview and gridview any one)


recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            // Stop only scrolling.
            return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
        }
    });


The REAL REAL answer is: For API 21 and higher:

No java code needed. You can set android:nestedScrollingEnabled="false" in xml:

<android.support.v7.widget.RecyclerView
     android:id="@+id/recycler"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:clipToPadding="true"
     android:nestedScrollingEnabled="false"
     tools:listitem="@layout/adapter_favorite_place">

There is a realy simple answer.

LinearLayoutManager lm = new LinearLayoutManager(getContext()) {
                @Override
                public boolean canScrollVertically() {
                    return false;
                }
            };

The above code disables RecyclerView vertically scrolling.


For whom want's to just prevent the user to scroll the RecyclerView, without loose the smoothScrollToPosition or any other "go to position" method, I'd recommend rather extending the RecyclerView class, overriding the onTouchEvent. Like this:

            public class HardwareButtonsRecyclerView extends RecyclerView {
            
                    public HardwareButtonsRecyclerView(@NonNull Context context) {
                        super(context);
                    }
            
                    public HardwareButtonsRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
                        super(context, attrs);
                    }
            
                    public HardwareButtonsRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
                        super(context, attrs, defStyleAttr);
                    }
            
                @Override
                public boolean onTouchEvent(MotionEvent e) {
                    return false;
                }
            }

I have been struggling in this issue for some hour, So I would like to share my experience, For the layoutManager solution it is fine but if u want to reEnable scrolling the recycler will back to top.

The best solution so far (for me at least) is using @Zsolt Safrany methode but adding getter and setter so you don't have to remove or add the OnItemTouchListener.

As follow

public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener {

    boolean isEnable = true;

    public RecyclerViewDisabler(boolean isEnable) {
        this.isEnable = isEnable;
    }

    public boolean isEnable() {
        return isEnable;
    }

    public void setEnable(boolean enable) {
        isEnable = enable;
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        return !isEnable;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {}

   @Override
   public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept){}
 }

Usage

RecyclerViewDisabler disabler = new RecyclerViewDisabler(true);
feedsRecycler.addOnItemTouchListener(disabler);

// TO ENABLE/DISABLE JUST USE THIS
disabler.setEnable(enable);

There is a more straightforward way to disable scrolling (technically it is more rather interception of a scrolling event and ending it when a condition is met), using just standard functionality. RecyclerView has the method called addOnScrollListener(OnScrollListener listener), and using just this you can stop it from scrolling, just so:

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        if (viewModel.isItemSelected) {
            recyclerView.stopScroll();
        }
    }
});

Use case: Let's say that you want to disable scrolling when you click on one of the items within RecyclerView so you could perform some actions with it, without being distracted by accidentally scrolling to another item, and when you are done with it, just click on the item again to enable scrolling. For that, you would want to attach OnClickListener to every item within RecyclerView, so when you click on an item, it would toggle isItemSelected from false to true. This way when you try to scroll, RecyclerView will automatically call method onScrollStateChanged and since isItemSelected set to true, it will stop immediately, before RecyclerView got the chance, well... to scroll.

Note: for better usability, try to use GestureListener instead of OnClickListener to prevent accidental clicks.


The real answer is

recyclerView.setNestedScrollingEnabled(false);

More info in documentation


You should just add this line:

recyclerView.suppressLayout(true)

Create class which extend RecyclerView class

public class NonScrollRecyclerView extends RecyclerView {

    public NonScrollRecyclerView(Context context) {
        super(context);
    }

    public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public NonScrollRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

This will disable the scroll event, but not the click events

Use this in your XML do the following:

  <com.yourpackage.xyx.NonScrollRecyclerView 
     ...
     ... 
  />

Override onTouchEvent() and onInterceptTouchEvent() and return false if you don't need OnItemTouchListener at all. This does not disable OnClickListeners of ViewHolders.

public class ScrollDisabledRecyclerView extends RecyclerView {
    public ScrollDisabledRecyclerView(Context context) {
        super(context);
    }

    public ScrollDisabledRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollDisabledRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        return false;
    }
}

In Kotlin, if you don't want to create an extra class just for setting one value, you can create anonymous class from LayoutManager:

recyclerView.layoutManager = object : LinearLayoutManager(context) {
    override fun canScrollVertically(): Boolean = false
}

This a bit hackish workaround but it works; you can enable/disable scrolling in the RecyclerView.

This is an empty RecyclerView.OnItemTouchListener stealing every touch event thus disabling the target RecyclerView.

public class RecyclerViewDisabler implements RecyclerView.OnItemTouchListener {

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        return true;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

Using it:

RecyclerView rv = ...
RecyclerView.OnItemTouchListener disabler = new RecyclerViewDisabler();

rv.addOnItemTouchListener(disabler);        // disables scolling
// do stuff while scrolling is disabled
rv.removeOnItemTouchListener(disabler);     // scrolling is enabled again 

Came across with a fragment that contains multiple RecycleView so I only need one scrollbar instead of one scrollbar in each RecycleView.

So I just put the ScrollView in the parent container that contains the 2 RecycleViews and use android:isScrollContainer="false" in the RecycleView

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="LinearLayoutManager"
    android:isScrollContainer="false" />

Another alternative is setLayoutFrozen, but it comes with a bunch of other side effects.

https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html#setLayoutFrozen(boolean)


For some reason @Alejandro Gracia answer starts working only after a few second. I found a solution that blocks the RecyclerView instantaneously:

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                return true;
            }
            @Override
            public void onTouchEvent(RecyclerView rv, MotionEvent e) {
            }
            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
            }
        });

Wrote a kotlin version:

class NoScrollLinearLayoutManager(context: Context?) : LinearLayoutManager(context) {
    private var scrollable = true

    fun enableScrolling() {
        scrollable = true
    }

    fun disableScrolling() {
        scrollable = false
    }

    override fun canScrollVertically() =
            super.canScrollVertically() && scrollable


    override fun canScrollHorizontally() =
            super.canScrollVertically()

 && scrollable
}

usage:

recyclerView.layoutManager = NoScrollLinearLayoutManager(context)
(recyclerView.layoutManager as NoScrollLinearLayoutManager).disableScrolling()

As setLayoutFrozen is deprecated, You can disable scrolling by freezing your RecyclerView by using suppressLayout.

To freeze:

recyclerView.suppressLayout(true)

To unfreeze:

recyclerView.suppressLayout(false)

At activity's onCreate method, you can simply do:

recyclerView.stopScroll()

and it stops scrolling.


This works for me:

  recyclerView.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
          return true;
      }
  });

You can add this line after setting your adapter

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

Now your recyclerview will work with smooth scrolling


If you just disable only scroll functionality of RecyclerView then you can use setLayoutFrozen(true); method of RecyclerView. But it can not be disable touch event.

your_recyclerView.setLayoutFrozen(true);

Here is how I did it with data binding:

            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipChildren="false"
                android:onTouch="@{(v,e) -> true}"/>

In place of the "true" I used a boolean variable that changed based on a condition so that the recycler view would switch between being disabled and enabled.


You can disable scrolling by freezing your RecyclerView.

To freeze: recyclerView.setLayoutFrozen(true)

To unfreeze: recyclerView.setLayoutFrozen(false)


Just add this to your recycleview in xml

 android:nestedScrollingEnabled="false"

like this

<android.support.v7.widget.RecyclerView
                    android:background="#ffffff"
                    android:id="@+id/myrecycle"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:nestedScrollingEnabled="false">

in XML :-

You can add

android:nestedScrollingEnabled="false"

in the child RecyclerView layout XML file

or

in Java :-

childRecyclerView.setNestedScrollingEnabled(false);

to your RecyclerView in Java code.

Using ViewCompat (Java) :-

childRecyclerView.setNestedScrollingEnabled(false); will work only in android_version>21 devices. to work in all devices use the following

ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);


Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to scroll

How to window.scrollTo() with a smooth effect Angular 2 Scroll to bottom (Chat style) Scroll to the top of the page after render in react.js Get div's offsetTop positions in React RecyclerView - How to smooth scroll to top of item on a certain position? Detecting scroll direction How to disable RecyclerView scrolling? How can I scroll a div to be visible in ReactJS? Make a nav bar stick Disable Scrolling on Body

Examples related to android-recyclerview

Failed to resolve: com.android.support:cardview-v7:26.0.0 android CardView background color always white Changing background color of selected item in recyclerview Simple Android grid example using RecyclerView with GridLayoutManager (like the old GridView) Simple Android RecyclerView example Android Horizontal RecyclerView scroll Direction Margin between items in recycler view Android How to add a recyclerView inside another recyclerView RecyclerView - Get view at particular position Recyclerview inside ScrollView not scrolling smoothly