Cómo deshabilitar el desplazamiento de RecyclerView?

No puedo deshabilitar el desplazamiento en RecyclerView . Intenté llamar a rv.setEnabled(false) pero aún puedo desplazarme.

¿Cómo puedo deshabilitar el desplazamiento?

Debe anular el administrador de disposición de su vista de reciclaje para esto. De esta forma solo deshabilitará el desplazamiento, ninguna de las otras funcionalidades. Aún podrá manejar el clic o cualquier otro evento táctil. Por ejemplo:-

Original:

  public class CustomGridLayoutManager extends LinearLayoutManager { private boolean isScrollEnabled = true; public CustomGridLayoutManager(Context context) { super(context); } public void setScrollEnabled(boolean flag) { this.isScrollEnabled = flag; } @Override public boolean canScrollVertically() { //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll return isScrollEnabled && super.canScrollVertically(); } } 

Aquí, usando el indicador “isScrollEnabled” puede habilitar / deshabilitar la funcionalidad de desplazamiento de su vista de reciclaje temporalmente.

También:

Simple anule su implementación existente para deshabilitar el desplazamiento y permitir hacer clic.

  linearLayoutManager = new LinearLayoutManager(context) { @Override public boolean canScrollVertically() { return false; } }; 

La verdadera respuesta es

 recyclerView.setNestedScrollingEnabled(false); 

Más información en documentación

Es una solución un tanto hackosa pero funciona; puede habilitar / deshabilitar el desplazamiento en RecyclerView .

Este es un RecyclerView.OnItemTouchListener vacío que roba cada evento táctil y desactiva el objective 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) { } } 

Utilizándolo:

 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 

Esto funciona para mí:

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

Para API 21 y superior:

No se necesita código java Puede configurar android:nestedScrollingEnabled="false" en xml:

  

Crear clase que amplíe la clase RecyclerView

  public class NonscrollRecylerview extends RecyclerView { public NonscrollRecylerview(Context context) { super(context); } public NonscrollRecylerview(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public NonscrollRecylerview(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(); } } 

Esto desactivará el evento de desplazamiento, pero no los eventos de clic

Use esto en su XML haga lo siguiente:

   ... ...  

Extienda el LayoutManager y anule canScrollHorizontally() y canScrollVertically() para deshabilitar el desplazamiento.

Tenga en cuenta que insertar elementos al principio no se desplazará automáticamente al principio, para evitar esto haga algo como:

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

Otra alternativa es setLayoutFrozen , pero viene con muchos otros efectos secundarios.

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

Sé que esto ya tiene una respuesta aceptada, pero la solución no tiene en cuenta un caso de uso que encontré.

Necesitaba específicamente un elemento de encabezado que aún se podía hacer clic, pero deshabilitaba el mecanismo de desplazamiento de RecyclerView. Esto se puede lograr con el siguiente código:

 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) { } }); 
 recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { // Stop only scrolling. return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING; } }); 

Por alguna razón, la respuesta de @Alejandro Gracia comienza a funcionar solo después de unos segundos. Encontré una solución que bloquea el RecyclerView de forma instantánea:

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

Anule onTouchEvent () y onInterceptTouchEvent () y devuelva false si no necesita OnItemTouchListener en absoluto. Esto no deshabilita OnClickListeners de 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; } } 

en XML: –

Puedes añadir

android:nestedScrollingEnabled="false"

en el archivo XML de diseño de RecyclerView secundario

o

en Java: –

childRecyclerView.setNestedScrollingEnabled(false);

a su RecyclerView en código Java.

Usando ViewCompat (Java): –

childRecyclerView.setNestedScrollingEnabled(false); funcionará solo en android_version> 21 dispositivos. para trabajar en todos los dispositivos, use la siguiente

ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);

Si solo deshabilita la funcionalidad de desplazamiento de RecyclerView , puede usar setLayoutFrozen(true); método de RecyclerView . Pero no se puede desactivar el evento táctil.

 your_recyclerView.setLayoutFrozen(true); 

He estado luchando en este tema durante una hora, así que me gustaría compartir mi experiencia. Para la solución de layoutManager está bien, pero si desea volver a desplazarse, la empresa de reciclaje volverá al principio.

La mejor solución hasta ahora (al menos para mí) es usar @Zsolt Safrany method pero agregar getter y setter para que no tenga que eliminar o agregar el OnItemTouchListener.

De la siguiente manera

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

Uso

 RecyclerViewDisabler disabler = new RecyclerViewDisabler(true); feedsRecycler.addOnItemTouchListener(disabler); // TO ENABLE/DISABLE JUST USE THIS disabler.setEnable(enable); 

Escribió una versión de kotlin:

 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 } 

uso:

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

Así es como lo hice con el enlace de datos:

   

En lugar del “verdadero” utilicé una variable booleana que cambió en función de una condición para que la vista del reciclador cambiara entre estar deshabilitada y habilitada.

Me encontré con un fragmento que contiene múltiples RecycleView, así que solo necesito una barra de desplazamiento en lugar de una barra de desplazamiento en cada RecycleView.

Así que simplemente puse ScrollView en el contenedor principal que contiene las 2 RecycleViews y uso android:isScrollContainer="false" en el RecycleView

  

Solo agregue esto a su vista de reciclaje en xml

  android:nestedScrollingEnabled="false" 

Me gusta esto

  

Añadir

 android:descendantFocusability="blocksDescendants" 

en su hijo de SrollView o NestedScrollView (y padre de ListView, recyclerview y gridview cualquiera)

Hay una forma más directa de deshabilitar el desplazamiento, utilizando solo la funcionalidad estándar. RecyclerView tiene el método llamado addOnScrollListener(OnScrollListener listener) , y usando solo esto puedes evitar que se desplace, solo así:

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

Caso de uso: supongamos que desea deshabilitar el desplazamiento cuando hace clic en uno de los elementos dentro de RecyclerView para que pueda realizar algunas acciones con él, sin distraerse desplazándose accidentalmente a otro elemento, y cuando haya terminado con él, simplemente haga clic en el elemento de nuevo para habilitar el desplazamiento. Para eso, querría conectar OnClickListener a cada elemento dentro de RecyclerView , de modo que cuando haga clic en un elemento, alternará isItemSelected de false a true . De esta forma, cuando intentes desplazarte, RecyclerView llamará automáticamente al método onScrollStateChanged y, dado que isItemSelected establece en true , se detendrá inmediatamente, antes de que RecyclerView tenga la oportunidad, bueno … de desplazarse.

Nota: para una mejor usabilidad, intente utilizar GestureListener lugar de OnClickListener para evitar clics accidental .