Comment désactiver le défilement RecyclerView?

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

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

    Pour cela, vous devez remplacer le gestionnaire de mise en page de votre recycleview. De cette façon, il ne fera que désactiver le défilement, 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 l’indicateur “isScrollEnabled”, vous pouvez activer / désactiver temporairement la fonctionnalité de défilement de votre vue de recyclage.

    Aussi:

    Simplifiez simplement votre implémentation existante pour désactiver le défilement et permettre le clic.

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

    La vraie réponse est

     recyclerView.setNestedScrollingEnabled(false); 

    Plus d’infos dans la documentation

    Cette solution de contournement un peu piratée, mais ça marche; vous pouvez activer / désactiver le défilement dans RecyclerView .

    Ceci est un RecyclerView.OnItemTouchListener vide qui vole chaque événement tactile, désactivant ainsi le RecyclerView cible.

     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 

    Cela fonctionne pour moi:

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

    Pour API 21 et supérieur:

    Aucun code Java nécessaire. Vous pouvez définir android:nestedScrollingEnabled="false" dans XML:

      

    Créer une classe qui étend la classe RecyclerView

      public class NonscrollRecylerview extends RecyclerView { public NonscrollRecylerview(Context context) { super(context); } public NonscrollRecylerview(Context context, @Nullable AtsortingbuteSet attrs) { super(context, attrs); } public NonscrollRecylerview(Context context, @Nullable AtsortingbuteSet 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 pour faire ce qui suit:

       ... ...  

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

    Sachez que l’insertion d’éléments au début ne fera pas défiler automatiquement le début, pour contourner ce problème, procédez comme suit:

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

    Une autre alternative est setLayoutFrozen , mais elle setLayoutFrozen autres effets secondaires.

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

    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 spécifiquement besoin d’un élément d’en-tête qui était encore cliquable, mais désactivait 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) { } }); 
     recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { // Stop only scrolling. return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING; } }); 

    Pour une raison quelconque, la réponse à @Alejandro Gracia ne commence à fonctionner qu’après quelques secondes. J’ai trouvé une solution qui bloque instantanément 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) { } }); 

    Remplacez onTouchEvent () et onInterceptTouchEvent () et retournez false si vous n’avez pas besoin de OnItemTouchListener. Cela ne désactive pas OnClickListeners de ViewHolders.

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

    Vous pouvez append

    android:nestedScrollingEnabled="false"

    dans le fichier XML de mise en page RecyclerView enfant

    ou

    en Java: –

    childRecyclerView.setNestedScrollingEnabled(false);

    à votre RecyclerView en code Java.

    Utilisation de ViewCompat (Java): –

    childRecyclerView.setNestedScrollingEnabled(false); ne fonctionnera que dans android_version> 21 périphériques. pour travailler dans tous les appareils, utilisez ce qui suit

    ViewCompat.setNestedScrollingEnabled(childRecyclerView, false);

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

     your_recyclerView.setLayoutFrozen(true); 

    Je me suis débattu dans ce problème pendant une heure, alors je voudrais partager mon expérience. Pour la solution layoutManager, c’est bien, mais si vous voulez réactiver le défilement, le recycleur sera au top.

    La meilleure solution à ce jour (pour moi au moins) est d’utiliser la méthode @Zsolt Safrany, mais en ajoutant getter et setter, vous n’avez donc pas à supprimer ou à append 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); 

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

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

       

    A la place du “vrai”, j’ai utilisé une variable booléenne qui changeait en fonction d’une condition, de sorte que la vue du recycleur bascule entre être désactivé et activé.

    Avec un fragment contenant plusieurs RecycleView, je n’ai besoin que d’une seule barre de défilement au lieu d’une seule barre de défilement dans chaque recycleView.

    Donc, je viens de mettre le ScrollView dans le conteneur parent qui contient les 2 RecycleViews et d’utiliser android:isScrollContainer="false" dans le RecycleView

      

    Ajoutez simplement ceci à votre recycleview dans xml

      android:nestedScrollingEnabled="false" 

    comme ça

      

    Ajouter

     android:descendantFocusability="blocksDescendants" 

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

    Il existe un moyen plus simple de désactiver le défilement, en utilisant uniquement des fonctionnalités standard. RecyclerView a la méthode appelée addOnScrollListener(OnScrollListener listener) , et en utilisant simplement ceci, vous pouvez l’empêcher de défiler, juste pour:

     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 RecyclerView pour pouvoir effectuer certaines actions sans être distrait par un défilement accidentel vers un autre élément. Cliquez simplement sur sur l’élément à nouveau pour activer le défilement. Pour cela, vous souhaitez attacher OnClickListener à chaque élément de RecyclerView . Ainsi, lorsque vous cliquez sur un élément, il bascule isItemSelected de false à true . De cette façon, lorsque vous essayez de faire défiler, RecyclerView appelle automatiquement la méthode onScrollStateChanged et depuis que isItemSelected défini sur true , il s’arrête immédiatement avant que RecyclerView ait la chance de bien défiler.

    Remarque: pour une meilleure convivialité, essayez d’utiliser GestureListener au lieu d’ OnClickListener pour éviter accidental clics accidental .