web-dev-qa-db-fra.com

Comment désactiver le défilement RecyclerView?

Je ne peux pas désactiver le défilement dans la RecyclerView. J'ai essayé d'appeler rv.setEnabled(false) mais je peux toujours faire défiler.

Comment puis-je désactiver le défilement?

145
Zsolt Safrany

Vous devez remplacer le layoutmanager de votre recycleview pour cela. De cette façon, le défilement ne sera désactivé que par aucune des autres fonctionnalités. Vous pourrez toujours gérer le clic ou tout autre événement tactile. Par exemple:-

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

En utilisant le drapeau "isScrollEnabled", vous pouvez activer/désactiver temporairement la fonctionnalité de défilement de votre vue recyclée.

Également:

Remplacez simplement votre implémentation existante pour désactiver le défilement et autoriser les clics.

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

La vraie réponse est 

recyclerView.setNestedScrollingEnabled(false);

Plus d'infos dans documentation

106
Bozic Nebojsa

Cette solution de contournement est un peu féroce, mais cela fonctionne. vous pouvez activer/désactiver le défilement dans la variable RecyclerView.

Il s'agit d'un RecyclerView.OnItemTouchListener vide volant tous les événements tactiles, désactivant ainsi la cible 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) {

    }
}

En l'utilisant:

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 
41
Zsolt Safrany

Pour API 21 et supérieur:

Aucun code Java nécessaire. Vous pouvez définir Android:nestedScrollingEnabled="false" en 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">
27
Milad Faridnia

Cela fonctionne pour moi: 

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

Créer une classe qui étend RecyclerView class

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

Cela désactivera l'événement de défilement, mais pas les événements de clic

Utilisez ceci dans votre XML, procédez comme suit:

  <com.yourpackage.xyx.NonscrollRecylerview 
 ...
 ... >

 ...
 ...

</com.yourpackage.xyz.NonscrollRecylerview >
8
Ashish

Si vous désactivez simplement uniquement la fonctionnalité de défilement de RecyclerView, vous pouvez utiliser la méthode setLayoutFrozen(true); de RecyclerView. Mais il ne peut pas être désactiver événement tactile.

your_recyclerView.setLayoutFrozen(true);
6
Ekta Bhawsar

Une autre alternative est setLayoutFrozen, mais elle entraîne de nombreux autres effets secondaires.

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

5
Taig

Vous pouvez désactiver le défilement en gelant votre RecyclerView.

Pour geler: recyclerView.setLayoutFrozen(true)

Pour dégeler: recyclerView.setLayoutFrozen(false)

4
Virat Singh

Étendez la LayoutManager et remplacez canScrollHorizontally()et canScrollVertically() pour désactiver le défilement.

Sachez que l'insertion d'éléments au début ne vous ramènera pas automatiquement au début.

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

3
rajesh

Je sais que cela a déjà une réponse acceptée, mais la solution ne prend pas en compte un cas d'utilisation que j'ai rencontré.

J'avais précisément besoin d'un élément d'en-tête sur lequel on pouvait toujours cliquer, tout en désactivant le mécanisme de défilement de RecyclerView. Cela peut être accompli avec le code suivant:

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

                    }
                });
3
Ryan Simon

A écrit une version 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
}

usage:

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

Remplacez onTouchEvent () et onInterceptTouchEvent () et renvoyez false si vous n'avez pas besoin de OnItemTouchListener du tout . Cela ne désactive pas 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;
    }
}
2
ypresto

Pour une raison quelconque, @Alejandro Gracia answer commence à travailler seulement après quelques secondes . J'ai trouvé une solution qui bloque instantanément le RecyclerView:

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

Cela fait quelque heure que je me bats dans ce numéro, Je voudrais donc partager mon expérience, Pour la solution de layoutManager, c’est bien, mais si vous voulez réactiver le défilement, le recycleur reviendra au début.

La meilleure solution à ce jour (du moins pour moi) consiste à utiliser la méthode @Zsolt Safrany, mais à ajouter getter et setter afin que vous n'ayez pas à supprimer ou à ajouter OnItemTouchListener.

Comme suit

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);
1
Aladdin

Confronté à un fragment contenant plusieurs RecycleView, je n'ai besoin que d'une barre de défilement au lieu d'une barre de défilement dans chaque RecycleView.

Donc, je viens de mettre le ScrollView dans le conteneur parent qui contient les 2 RecycleViews et utiliser Android:isScrollContainer="false" dans le 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" />
0
pk028382

Il existe un moyen plus simple de désactiver le défilement, en utilisant uniquement les fonctionnalités standard. RecyclerView a la méthode appelée addOnScrollListener(OnScrollListener listener), et en utilisant simplement ceci, vous pouvez l'arrêter du défilement, juste comme ceci:

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

Cas d'utilisation: Supposons que vous souhaitiez désactiver le défilement lorsque vous cliquez sur l'un des éléments de la variable RecyclerView pour pouvoir effectuer certaines opérations sans être distrait en passant accidentellement à un autre élément, et lorsque vous terminé, il suffit de cliquer à nouveau sur l'élément pour activer le défilement. Pour cela, vous voudriez attacher OnClickListener à chaque élément de RecyclerView. Ainsi, lorsque vous cliquez sur un élément, il basculera isItemSelected de false à true. Ainsi, lorsque vous essayez de faire défiler, RecyclerView appellera automatiquement la méthode onScrollStateChanged et puisque isItemSelected a la valeur true, elle s’arrêtera immédiatement, avant que RecyclerView ne puisse faire défiler.

Remarque: pour améliorer la convivialité, essayez d'utiliser GestureListener au lieu de OnClickListener pour empêcher les clics accidental.

0
Tim Jorjev

Vous pouvez ajouter cette ligne après avoir configuré votre adaptateur

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

Maintenant, votre liste de recyclage fonctionnera avec un défilement régulier

0
Atefeh Srch

Voici comment je l'ai fait avec la liaison de données:

            <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}"/>

À la place du "vrai", j'ai utilisé une variable booléenne modifiée en fonction d'une condition permettant à la vue du recycleur de basculer entre désactivée et activée.

0
bwhite

Ajoutez simplement ceci à votre recycleview en xml

 Android:nestedScrollingEnabled="false"

comme ça

<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">
0
anas

Il y a une réponse très simple.

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

Le code ci-dessus désactive le défilement vertical de RecyclerView.

0
Emi Raz

Ajouter

Android:descendantFocusability="blocksDescendants"

dans votre enfant de SrollView ou NestedScrollView (et parent de ListView, recyclerview et gridview)

0
Pankaj Talaviya