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?
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:-
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.
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;
}
};
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
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">
Cela fonctionne pour moi:
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
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 >
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);
Une autre alternative est setLayoutFrozen
, mais elle entraîne de nombreux autres effets secondaires.
Vous pouvez désactiver le défilement en gelant votre RecyclerView.
Pour geler: recyclerView.setLayoutFrozen(true)
Pour dégeler: recyclerView.setLayoutFrozen(false)
É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);
}
}
}
});
}
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
// Stop only scrolling.
return rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING;
}
});
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) {
}
});
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()
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;
}
}
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) {
}
});
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);
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" />
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
.
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
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.
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">
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.
Ajouter
Android:descendantFocusability="blocksDescendants"
dans votre enfant de SrollView ou NestedScrollView (et parent de ListView, recyclerview et gridview)