J'ai passé un moment à essayer de trouver un moyen d'ajouter un en-tête à un RecyclerView
, sans succès.
Voici ce que j'ai obtenu jusqu'à présent:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
layouManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layouManager);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
headerPlaceHolder = inflater.inflate(R.layout.view_header_holder_medium, null, false);
layouManager.addView(headerPlaceHolder, 0);
...
}
Le LayoutManager
semble être l'objet qui gère la disposition des RecyclerView
éléments. Comme je ne pouvais trouver aucune addHeaderView(View view)
méthode, je décide d'aller avec le LayoutManager
de » addView(View view, int position)
méthode et d'ajouter mon point de vue d' en- tête dans la première position d'agir comme un en- tête.
Et c'est là que les choses deviennent plus laides:
java.lang.NullPointerException: Attempt to read from field 'android.support.v7.widget.RecyclerView$ViewHolder android.support.v7.widget.RecyclerView$LayoutParams.mViewHolder' on a null object reference
at android.support.v7.widget.RecyclerView.getChildViewHolderInt(RecyclerView.java:2497)
at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:4807)
at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:4803)
at com.mathieumaree.showz.fragments.CategoryFragment.setRecyclerView(CategoryFragment.java:231)
at com.mathieumaree.showz.fragments.CategoryFragment.access$200(CategoryFragment.java:47)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:201)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:196)
at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:41)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Après avoir NullPointerExceptions
essayé plusieurs fois d'appeler le addView(View view)
à différents moments de la création de l'activité (j'ai également essayé d'ajouter la vue une fois que tout est configuré, même les données de l'adaptateur), j'ai réalisé que je n'avais aucune idée si c'était la bonne façon de le faire (et il ne semble pas être).
PS: Aussi, une solution qui pourrait gérer le GridLayoutManager
en plus de la LinearLayoutManager
serait vraiment appréciée!
la source
Réponses:
J'ai dû ajouter un pied de page à mon
RecyclerView
et ici je partage mon extrait de code car je pensais que cela pourrait être utile. Veuillez vérifier les commentaires à l'intérieur du code pour une meilleure compréhension du flux global.L'extrait de code ci-dessus ajoute un pied de page au
RecyclerView
. Vous pouvez vérifier ce référentiel GitHub pour vérifier l'implémentation de l'ajout d'un en-tête et d'un pied de page.la source
RecyclerView
fichier dynamiquement. Vous pouvez avoir le contrôle sur chacun des éléments de votreRecyclerView
. Veuillez consulter la section code pour un projet de travail. J'espère que cela pourrait aider. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Renvoie le type de vue de l'élément à la position à des fins de recyclage de vue. L'implémentation par défaut de cette méthode renvoie 0, faisant l'hypothèse d'un seul type de vue pour l'adaptateur. Contrairement auxListView
adaptateurs, les types n'ont pas besoin d'être contigus. Envisagez d'utiliser des ressources d'identifiant pour identifier de manière unique les types de vues d'élément. - De la documentation. developer.android.com/reference/android/support/v7/widget/…Très simple à résoudre !!
Je n'aime pas l'idée d'avoir la logique à l'intérieur de l'adaptateur comme type de vue différent, car chaque fois qu'il vérifie le type de vue avant de renvoyer la vue. La solution ci-dessous évite les contrôles supplémentaires.
Ajoutez simplement la vue d'en-tête LinearLayout (vertical) + la vue de recyclage + la vue de pied de page dans android.support.v4.widget.NestedScrollView .
Regarde ça:
Ajoutez cette ligne de code pour un défilement fluide
Cela perdra toutes les performances du VR et RV essaiera de disposer tous les détenteurs de vue quel que soit le
layout_height
RV.Utilisation recommandée pour la liste de petite taille comme le tiroir de navigation ou les paramètres, etc.
la source
RecyclerView
apporte - vous perdez le recyclage réel et l'optimisation qu'il apporte.J'ai eu le même problème sur Lollipop et j'ai créé deux approches pour envelopper l'
Recyclerview
adaptateur. L'un est assez facile à utiliser, mais je ne sais pas comment il se comportera avec un ensemble de données changeant. Parce qu'il enveloppe votre adaptateur et que vous devez vous assurer d'appeler des méthodes commenotifyDataSetChanged
sur le bon objet adaptateur.L'autre ne devrait pas avoir de tels problèmes. Laissez simplement votre adaptateur régulier étendre la classe, implémentez les méthodes abstraites et vous devriez être prêt. Et les voici:
l'essentiel
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Commentaires et fourchettes appréciés. Je vais utiliser
HeaderRecyclerViewAdapterV2
par moi-même et évoluer, tester et publier les changements dans le futur.EDIT : @OvidiuLatcu Oui, j'ai eu quelques problèmes. En fait, j'ai arrêté de compenser implicitement l'en-tête par
position - (useHeader() ? 1 : 0)
et j'ai plutôt créé une méthode publiqueint offsetPosition(int position)
pour cela. Parce que si vous définissez unOnItemTouchListener
Recyclerview, vous pouvez intercepter le toucher, obtenir les coordonnées x, y du toucher, trouver la vue enfant correspondante , puis appelerrecyclerView.getChildPosition(...)
et vous obtiendrez toujours la position non décalée dans l'adaptateur! Ceci est un raccourci dans le code RecyclerView, je ne vois pas de méthode facile pour surmonter cela. C'est pourquoi je décale maintenant les positions explicites quand j'en ai besoin par mon propre code.la source
Je n'ai pas essayé cela, mais j'ajouterais simplement 1 (ou 2, si vous voulez à la fois un en-tête et un pied de page) à l'entier retourné par getItemCount dans votre adaptateur. Vous pouvez ensuite remplacer
getItemViewType
dans votre adaptateur pour renvoyer un entier différent lorsquei==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
est ensuite passé l'entier que vous avez renvoyégetItemViewType
, vous permettant de créer ou de configurer différemment le support de vue pour la vue d'en-tête: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , int)N'oubliez pas de soustraire un de l'entier de position passé à
bindViewHolder
.la source
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(RecyclerView
n'a pas degetViewTypeCount()
méthode). D'un autre côté, je suis d'accord avec @IZI_Shadow_IZI, j'ai vraiment le sentiment que le LayoutManager devrait être celui qui gère ce genre de choses. Une autre idée?Vous pouvez utiliser cette bibliothèque GitHub permettant d'ajouter un en- tête et / ou un pied de page dans votre RecyclerView de la manière la plus simple possible.
Vous devez ajouter la bibliothèque HFRecyclerView dans votre projet ou vous pouvez également la récupérer à partir de Gradle:
Ceci est un résultat en image:
ÉDITER:
Si vous souhaitez simplement ajouter une marge en haut et / ou en bas avec cette bibliothèque: SimpleItemDecoration :
la source
J'ai fini par implémenter mon propre adaptateur pour envelopper tout autre adaptateur et fournir des méthodes pour ajouter des vues d'en-tête et de pied de page.
Créé un résumé ici: HeaderViewRecyclerAdapter.java
La principale fonctionnalité que je voulais était une interface similaire à une ListView, je voulais donc pouvoir gonfler les vues dans mon Fragment et les ajouter au
RecyclerView
inonCreateView
. Cela se fait en créant unHeaderViewRecyclerAdapter
passage de l'adaptateur à encapsuler, et en appelantaddHeaderView
et enaddFooterView
passant vos vues gonflées. Définissez ensuite l'HeaderViewRecyclerAdapter
instance en tant qu'adaptateur sur leRecyclerView
.Une exigence supplémentaire était que je devais être en mesure de remplacer facilement les adaptateurs tout en conservant les en-têtes et les pieds de page, je ne voulais pas avoir plusieurs adaptateurs avec plusieurs instances de ces en-têtes et pieds de page. Vous pouvez donc appeler
setAdapter
pour changer l'adaptateur enveloppé en laissant les en-têtes et les pieds de page intacts, enRecyclerView
étant averti du changement.la source
ma façon "Keep it simple stupid" ... ça gaspille des ressources, je sais, mais je m'en fiche car mon code reste simple alors ... 1) ajouter un pied de page avec visibilité GONE à votre item_layout
2) puis mettez-le visible sur le dernier élément
faire le contraire pour l'en-tête
la source
Sur la base de la solution de @ seb, j'ai créé une sous-classe de RecyclerView.Adapter qui prend en charge un nombre arbitraire d'en-têtes et de pieds de page.
https://gist.github.com/mheras/0908873267def75dc746
Bien que cela semble être une solution, je pense également que cette chose devrait être gérée par le LayoutManager. Malheureusement, j'en ai besoin maintenant et je n'ai pas le temps d'implémenter un StaggeredGridLayoutManager à partir de zéro (ni même de l'étendre).
Je suis toujours en train de le tester, mais vous pouvez l'essayer si vous le souhaitez. Veuillez me faire savoir si vous rencontrez des problèmes avec celui-ci.
la source
Vous pouvez utiliser viewtype pour résoudre ce problème, voici ma démo: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
vous pouvez définir un mode d'affichage de la vue recycleur:
public static final int MODE_DATA = 0, MODE_LOADING = 1, MODE_ERROR = 2, MODE_EMPTY = 3, MODE_HEADER_VIEW = 4, MODE_FOOTER_VIEW = 5;
2. outrepasser le mothod getItemViewType
3. outrepasser la méthode getItemCount
4. annulez la méthode onCreateViewHolder. créer un support de vue par viewType
5. Remplacez la méthode onBindViewHolder. lier les données par viewType
la source
Vous pouvez utiliser la bibliothèque SectionedRecyclerViewAdapter pour regrouper vos éléments en sections et ajouter un en-tête à chaque section, comme sur l'image ci-dessous:
Commencez par créer votre classe de section:
Ensuite, vous configurez RecyclerView avec vos sections et modifiez le SpanSize des en-têtes avec un GridLayoutManager:
la source
Je sais que j'arrive en retard, mais ce n'est que récemment que j'ai pu implémenter un tel "addHeader" sur l'adaptateur. Dans mon projet FlexibleAdapter , vous pouvez appeler
setHeader
un élément Sectionable , puis vous appelezshowAllHeaders
. Si vous n'avez besoin que d'un seul en-tête, le premier élément doit avoir l'en-tête. Si vous supprimez cet élément, l'en-tête est automatiquement lié au suivant.Malheureusement, les pieds de page ne sont pas (encore) couverts.
Le FlexibleAdapter vous permet de faire bien plus que de créer des en-têtes / sections. Vous devriez vraiment jeter un coup d'œil: https://github.com/davideas/FlexibleAdapter .
la source
Je voudrais simplement ajouter une alternative à toutes ces implémentations de HeaderRecyclerViewAdapter. CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
C'est une approche plus flexible, car vous pouvez créer un AdapterGroup à partir des adaptateurs. Pour l'exemple d'en-tête, utilisez votre adaptateur tel quel, avec un adaptateur contenant un élément pour l'en-tête:
C'est assez simple et lisible. Vous pouvez facilement implémenter un adaptateur plus complexe en utilisant le même principe.
la source
recyclerview:1.2.0
introduit la classe ConcatAdapter qui concatène plusieurs adaptateurs en un seul. Cela permet donc de créer des adaptateurs d'en-tête / pied de page séparés et de les réutiliser sur plusieurs listes.Jetez un œil à l' article d'annonce . Il contient un exemple d'affichage de la progression du chargement dans l'en-tête et le pied de page à l'aide de
ConcatAdapter
.Pour le moment où je poste cette réponse, la version
1.2.0
de la bibliothèque est en phase alpha, donc l'API pourrait changer. Vous pouvez vérifier le statut ici .la source