Comment utiliser RecyclerView
dans NestedScrollView
? RecyclerView
le contenu n'est pas visible après avoir défini l'adaptateur.
UPDATEcode de mise en page mis à jour.
<Android.support.v4.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical">
<RelativeLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:padding="@dimen/keyline_1">
</RelativeLayout>
<View
Android:id="@+id/separator"
Android:layout_width="match_parent"
Android:layout_height="1dp"
Android:background="#e5e5e5" />
<Android.support.v7.widget.RecyclerView
Android:id="@+id/conversation"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</LinearLayout>
</Android.support.v4.widget.NestedScrollView>
Remplacez votre recyclerView par,
<Android.support.v7.widget.RecyclerView
Android:id="@+id/conversation"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
ici,
app:layout_behavior="@string/appbar_scrolling_view_behavior"
va gérer le reste des choses.
Une dernière chose, pas besoin de mettre votre recyclerView dans NestedScrollView
UPDATE 1
Depuis Android Support Library 23.2.0, la méthode setAutoMeasureEnabled(true)
a été ajoutée pour LayoutManagers. Cela permet à RecyclerView d'envelopper son contenu et fonctionne à merveille.
http://Android-developers.blogspot.ru/2016/02/Android-support-library-232.html
Alors, ajoutez quelque chose comme ceci:
LayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setAutoMeasureEnabled(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setNestedScrollingEnabled(false);
UPDATE 2
Puisque 27.1.0 setAutoMeasureEnabled
est obsolète, vous devez donc fournir une implémentation personnalisée de LayoutManager avec la méthode substituée isAutoMeasureEnabled()
Mais après de nombreux cas d’utilisation, RecyclerView est fortement déconseillé de l’utiliser en mode wrapping} _, car ce n’est pas son objectif. Essayez de refactoriser toute votre mise en page à l’aide de RecyclerView unique et normal avec plusieurs types d’éléments. Ou utilisez l'approche avec LinearLayout que j'ai décrite ci-dessous en dernier recours
Ancienne réponse (non recommandé)
Vous pouvez utiliser RecyclerView
à l'intérieur de NestedScrollView
. Tout d'abord, vous devez implémenter votre propre LinearLayoutManager
personnalisée, cela permet à votre RecyclerView
d'envelopper son contenu. Par exemple:
public class WrappingLinearLayoutManager extends LinearLayoutManager
{
public WrappingLinearLayoutManager(Context context) {
super(context);
}
private int[] mMeasuredDimension = new int[2];
@Override
public boolean canScrollVertically() {
return false;
}
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
if (getOrientation() == HORIZONTAL) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
heightSpec,
mMeasuredDimension);
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
measureScrapChild(recycler, i,
widthSpec,
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view.getVisibility() == View.GONE) {
measuredDimension[0] = 0;
measuredDimension[1] = 0;
return;
}
// For adding Item Decor Insets to view
super.measureChildWithMargins(view, 0, 0);
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
p.height);
view.measure(childWidthSpec, childHeightSpec);
// Get decorated measurements
measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
Après cela, utilisez cette LayoutManager
pour votre RecyclerView
recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
Mais vous devriez aussi appeler ces deux méthodes:
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Ici, setNestedScrollingEnabled(false)
désactive le défilement de RecyclerView
, de sorte qu'il n'intercepte pas l'événement de défilement de NestedScrollView
. Et setHasFixedSize(false)
détermine que les modifications apportées au contenu de l'adaptateur peuvent modifier la taille de la variable RecyclerView
.
Remarque importante: Cette solution est parfois problématique et pose des problèmes de performances. Par conséquent, si vous avez beaucoup d'éléments dans votre RecyclerView
, je vous recommande d'utiliser l'implémentation personnalisée de la vue liste basée sur LinearLayout
, créez un analogue de Adaptateur pour lui et le faire se comporter comme ListView
ou RecyclerView
1) Vous devez utiliser la bibliothèque de support 23.2.0 (ou) ci-dessus
2) et RecyclerView
height sera wrap_content
.
3) recyclerView.setNestedScrollingEnabled(false)
Mais en faisant cela, le modèle de recycleur ne fonctionne pas. (c’est-à-dire que toutes les vues seront chargées en même temps, car wrap_content
a besoin de la hauteur de RecyclerView
complet pour pouvoir dessiner tous les enfants View
s à la fois. Aucune vue ne sera recyclée). Essayez de ne pas utiliser ce motif, sauf si c'est vraiment nécessaire. Essayez d'utiliser viewType
et ajoutez toutes les autres vues qui doivent défiler jusqu'à RecyclerView
plutôt que d'utiliser RecyclerView
dans Scrollview
. L'impact sur les performances sera très élevé.
Pour simplifier, "cela agit simplement comme LinearLayout
avec toutes les vues enfant"
Vous pouvez utiliser Android:fillViewport="true"
pour que NestedScrollView
mesure la RecyclerView
. La RecyclerView
remplira la hauteur restante. donc si vous voulez faire défiler la NestScrollView
, vous pouvez définir la RecyclerView
's minHeight
.
Ajouter simplement recyclerView.setNestedScrollingEnabled(false);
avant setAdapter
lui-même a fonctionné pour moi. Je n'ai pas ajouté app:layout_behavior="@string/appbar_scrolling_view_behavior"
nulle part et je n'ai défini aucun gestionnaire de présentation personnalisé.
<Android.support.v4.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/white"
Android:orientation="vertical">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_marginLeft="15dp"
Android:layout_marginRight="15dp"
Android:orientation="vertical">
<TextView
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:textColor="@color/white"
Android:text="Some Text..."
Android:padding="15dp" />
</LinearLayout>
<LinearLayout
Android:orientation="vertical"
Android:padding="15dp"
Android:layout_marginTop="10dp"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<TextView
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:text="Quick Links"
Android:textColor="@color/black"
Android:textStyle="bold"
Android:textAllCaps="true"
Android:paddingLeft="20dp"
Android:drawableLeft="@drawable/ic_trending_up_black_24dp"
Android:drawablePadding="10dp"
Android:layout_marginBottom="10dp"
Android:textSize="16sp"/>
<View
Android:layout_width="fill_parent"
Android:layout_height="1dp"
Android:background="#efefef"/>
<Android.support.v7.widget.RecyclerView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/recyclerview"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
</Android.support.v4.widget.NestedScrollView>
C'est ce qui fonctionne pour moi
<Android.support.v4.widget.NestedScrollView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/rv_recycler_view"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</Android.support.v4.widget.NestedScrollView>
Essayez d'utiliser cette bibliothèque - https://github.com/serso/Android-linear-layout-manager .
LayoutManager de la bibliothèque permet à RecyclerView d’envelopper son contenu. Dans ce cas, RecyclerView sera "aussi grand que les vues intérieures", il n'aura donc pas de barre de défilement et l'utilisateur utilisera les capacités de défilement de NestedScrollView. Par conséquent, il ne sera pas ambigu comme "scrollable inside scrollable".
Il y a un code simple et de test que vous pouvez vérifier
<Android.support.v4.widget.NestedScrollView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<Android.support.v7.widget.RecyclerView
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
</Android.support.v4.widget.NestedScrollView>
J'ai utilisé RecyclerView à l'intérieur d'un NestedScrollView et cela a fonctionné pour moi. La seule chose que je devais garder à l'esprit était qu'un NestedScrollView ne prend qu'une seule vue enfant. Ainsi, dans mon cas, j’ai utilisé le groupe de visualisation LienearLayout, qui hébergeait mon RecyclerView, ainsi que plusieurs autres affichages dont j'avais besoin.
Je rencontre un problème en plaçant mon RecyclerView dans le NestedScrollView. J'ai réalisé que le défilement du contenu de mon RecyclerView était relâché.
J'ai par la suite réalisé que mon RecyclerView recevait l'événement de défilement et était donc en conflit avec le comportement de défilement de NestedScrollView.
Donc, pour résoudre ce problème, je devais désactiver la fonctionnalité de défilement de mon RecyclerView avec cette méthode movieListNewRecyclerView.setNestedScrollingEnabled(false);
Vous pouvez consulter mon Instagram pour une courte vidéo de ce que j'ai réellement fait. Ceci est mon identifiant Instagram ofelix03
Voici le code que j'utilise pour éviter les problèmes de défilement:
mRecyclerView = (RecyclerView) view.findViewById(Android.R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
J'ai Viewpager et RecyclerView à l'intérieur du NestedScrollView. Après avoir ajouté les lignes ci-dessous
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
J'ai résolu le problème du défilement lent et du décalage du défilement.
Si vous utilisez RecyclerView-23.2.1
ou une version ultérieure. La solution suivante fonctionnera parfaitement:
Dans votre mise en page, ajoutez RecyclerView comme ceci:
<Android.support.v7.widget.RecyclerView
Android:id="@+id/review_list"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:scrollbars="vertical" />
Et dans votre fichier Java:
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());
layoutManager.setAutoMeasureEnabled(true);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(new YourListAdapter(getContext()));
Ici, layoutManager.setAutoMeasureEnabled(true);
fera l'affaire.
Consultez ce numéro et ce blog de développeur pour plus d'informations.
Vous ne pouvez pas utiliser une vue de recycleur dans une vue de défilement imbriquée. La vue défilante imbriquée n’est pas destinée à contenir d’autres vues défilables, mais c’est parce que c’est un enfant d’une disposition défilante elle-même. J'avais le même problème, mais au final, j'ai déplacé ma vue texte pour qu'elle soit une vue d'ensemble dans la vue recyclée, j'ai fait de la vue recyclée un enfant direct de la présentation du coordinateur et j'ai supprimé la vue de défilement imbriquée. Puis tous mes problèmes ont disparu.
Il y a beaucoup de bonnes réponses. La clé est que vous devez définir nestedScrollingEnabled
sur false
. Comme mentionné ci-dessus, vous pouvez le faire en code Java:
mRecyclerView.setNestedScrollingEnabled(false);
Mais vous avez également la possibilité de définir la même propriété en code xml (Android:nestedScrollingEnabled="false"
):
<Android.support.v7.widget.RecyclerView
Android:id="@+id/recyclerview"
Android:nestedScrollingEnabled="false"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
Pour androidx
, il s'appelle androidx.core.widget.NestedScrollView
- et il fait également défiler les mêmes propriétés avec les propriétés isScrollContainer
et measureAllChildren
activées:
<!-- Scrolling Content -->
<androidx.core.widget.NestedScrollView
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:isScrollContainer="true"
Android:measureAllChildren="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
Android:id="@+id/recyclerview"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fastScrollEnabled="true"
Android:scrollbarStyle="insideInset"
Android:scrollbars="vertical"
Android:splitMotionEvents="false"
Android:verticalScrollbarPosition="right"/>
</androidx.core.widget.NestedScrollView>
Je devais mettre en œuvre CoordinatorLayout avec le défilement dans la barre d’outils et cela me prenait toute la journée. Je l'ai obtenu en supprimant NestedScrollView. Donc, j'utilise simplement RelativeLayout à la racine.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/rv_nearby"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</RelativeLayout>
n'utilisez pas recyclerView dans NestedScrollView. cela peut causer des problèmes en cascade! Je suggère d'utiliser ItemViewTypes dans RecyclerView pour gérer plusieurs types de vues. ajoutez simplement un RecyclerView avec match_parent largeur et hauteur. dans votre recyclerViewAdapter, substituez getItemViewType et utilisez position pour gérer la disposition à gonfler. Après cela, vous pouvez gérer votre détenteur de vue en utilisant la méthode onBindViewHolder.
Si vous utilisez RecyclerView ScrollListener à l'intérieur de NestedScrollView, l'écouteur addOnScrollListener ne fonctionne pas correctement si vous utilisez les deux.
Utilisez ce code.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
......
}
});
ce code fonctionne très bien RecyclerView ScrollListener à l'intérieur NestedScrollView.
merci
Une solution pour conserver la fonctionnalité de recyclage de Recyclage et éviter que Recyclage ne charge toutes vos données consiste à définir une hauteur fixe dans le Recyclage lui-même. En faisant cela, la vue de recyclage est limitée au chargement que sa hauteur peut montrer à l'utilisateur, recyclant ainsi son élément si jamais vous faites défiler vers le bas/haut.