Je cherche un équivalent à addHeaderView pour une vue recycleur. Fondamentalement, je veux qu'une image avec 2 boutons soit ajoutée comme en-tête à la liste. Existe-t-il une manière différente d'ajouter une vue d'en-tête à une vue de recycleur? Un exemple d'orientation serait utile
EDIT 2 (dispositions de fragments ajoutées):
Après avoir ajouté des instructions de journal, il semble que getViewType ne reçoive que la position 0. Cela conduit à onCreateView ne charger que la seule disposition:
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemCount: 5
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> getItemViewType position: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> onCreateViewHolder, viewtype: 0
10-26 16:32:53.766 5449-5449/co.testapp I/logger info﹕ Adapter-> onBindViewHolder, viewType: 0
La transition du fragment pour charger le CommentFragment:
@Override
public void onPhotoFeedItemClick(View view, int position) {
if (fragmentManager == null)
fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (view.getId() == R.id.button_comment){
CommentFragment commentFragment = CommentFragment.newInstance("","", position);
fragmentTransaction.add(R.id.main_activity, commentFragment,"comment_fragment_tag");
fragmentTransaction.addToBackStack(Constants.TAG_COMMENTS);
fragmentTransaction.commit();
}
}
OnCreateView du fragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_comment, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.list_recylclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(_context));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new CommentAdapter(R.layout.row_list_comments, R.layout.row_header_comments, _context, comments);
mRecyclerView.setAdapter(mAdapter);
return view;
}
Le fragment contenant la recycleview:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context="co.testapp.fragments.CommentFragment"
android:background="@color/white">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_recylclerview"
android:layout_width="match_parent"
android:layout_height="200dp" />
</RelativeLayout>
</RelativeLayout>
La disposition des lignes de commentaires:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_margin="10dp"
android:background="@color/white">
<!--Profile Picture-->
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:id="@+id/profile_picture"
android:background="@color/blue_testapp"/>
<!--Name-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="First Name Last Name"
android:textSize="16dp"
android:textColor="@color/blue_testapp"
android:id="@+id/name_of_poster"
android:layout_toRightOf="@id/profile_picture"
/>
<!--Comment-->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginTop="-5dp"
android:text="This is a test comment"
android:textSize="14dp"
android:textColor="@color/black"
android:id="@+id/comment"
android:layout_below="@id/name_of_poster"
android:layout_toRightOf="@id/profile_picture"/>
</RelativeLayout>
L'en-tête
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="300dp"
android:id="@+id/header_photo"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
Le code adaptateur (merci à hister de m'avoir aidé à démarrer):
public class CommentAdapter extends RecyclerView.Adapter<ViewHolder>{
private final int rowCardLayout;
public static Context mContext;
private final int headerLayout;
private final String [] comments;
private static final int HEADER = 0;
private static final int OTHER = 0;
public CommentAdapter(int rowCardLayout, int headerLayout, Context context, String [] comments) {
this.rowCardLayout = rowCardLayout;
this.mContext = context;
this.comments = comments;
this.headerLayout = headerLayout;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
logger.i("onCreateViewHolder, viewtype: " + i); //viewtype always returns 0 so OTHER layout is never inflated
if (i == HEADER) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(headerLayout, viewGroup, false);
return new ViewHolderHeader(v);
}
else if (i == OTHER){
View v = LayoutInflater.from(viewGroup.getContext()).inflate(rowCardLayout, viewGroup, false);
return new ViewHolderComments(v);
}
else
throw new RuntimeException("Could not inflate layout");
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
logger.i("onBindViewHolder, viewType: " + i);
if (viewHolder instanceof ViewHolderComments)
((ViewHolderComments) viewHolder).comment.setText(comments[i].toString());
if (viewHolder instanceof ViewHolderHeader)
((ViewHolderHeader) viewHolder).header.setImageResource(R.drawable.image2);
else {
logger.e("no instance of viewholder found");
}
}
@Override
public int getItemCount() {
int count = comments.length + 1;
logger.i("getItemCount: " + count);
return count;
}
@Override
public int getItemViewType(int position) {
logger.i("getItemViewType position: " + position);
if (position == HEADER)
return HEADER;
else
return OTHER;
}
public static class ViewHolderComments extends RecyclerView.ViewHolder {
public TextView comment;
public ImageView image;
public ViewHolderComments(View itemView) {
super(itemView);
comment = (TextView) itemView.findViewById(R.id.comment);
image = (ImageView) itemView.findViewById(R.id.image);
}
}
public static class ViewHolderHeader extends RecyclerView.ViewHolder {
public final ImageView header;
public ViewHolderHeader(View itemView){
super(itemView);
header = (ImageView) itemView.findViewById(R.id.header_photo);
}
}
}
En utilisant le code ci-dessus, seule la disposition d'en-tête est affichée car viewType est toujours 0. Il ressemble à ceci . Si je force l'autre disposition, cela ressemble à ceci :
la source
Réponses:
Il n'y a pas de moyen simple
listview.addHeaderView()
mais vous pouvez y parvenir en ajoutant un type à votre adaptateur pour l'en-tête.Voici un exemple
lien vers l'essentiel -> ici
la source
private String getItem(int position) { return data[position + 1]; }
Provoque un NPE. Étant donné que notre position a été augmentée d'une unité, en raison de l'en-tête, nous devons soustraire 1 pour obtenir l'élément correct de nos données [].private String getItem(int position) { return data[position - 1]; }
setSpanSizeLookup
pourGridLayoutManager
, de sorte que votre en-tête prendra toutes les colonnesFacile et réutilisable
ItemDecoration
Les en- têtes statiques peuvent facilement être ajoutés avec
ItemDecoration
et sans autres modifications.La décoration est également réutilisable car il n'est pas nécessaire de modifier l'adaptateur ou du
RecyclerView
tout.L'exemple de code fourni ci-dessous nécessitera une vue à ajouter en haut qui peut simplement être gonflée comme tout le reste. Cela peut ressembler à ceci:
Pourquoi statique ?
Si vous n'avez qu'à afficher du texte et des images, cette solution est pour vous - il n'y a aucune possibilité d'interaction avec l'utilisateur comme des boutons ou des pagers, car elle sera simplement dessinée en haut de votre liste.
Gestion des listes vides
S'il n'y a pas de vue à décorer, la décoration ne sera pas dessinée. Vous devrez toujours gérer vous-même une liste vide. (Une solution de contournement possible consiste à ajouter un élément factice à l'adaptateur.)
Le code
Vous pouvez trouver le code source complet ici sur GitHub, y compris un
Builder
pour aider à l'initialisation du décorateur, ou utilisez simplement le code ci-dessous et fournissez vos propres valeurs au constructeur.Assurez-vous de définir un correct
layout_height
pour votre vue. par exemplematch_parent
pourrait ne pas fonctionner correctement.Remarque: le projet GitHub est mon terrain de jeu personnel. Il n'est pas testé minutieusement, c'est pourquoi il n'y a pas encore de bibliothèque .
Qu'est ce que ça fait?
Un
ItemDecoration
dessin supplémentaire est ajouté à un élément d'une liste. Dans ce cas, une décoration est dessinée en haut du premier élément.La vue est mesurée et présentée, puis elle est dessinée en haut du premier élément. Si un effet de parallaxe est ajouté, il sera également coupé aux limites correctes.
la source
N'hésitez pas à utiliser ma bibliothèque, disponible ici .
Il vous permet de créer un en-tête
View
pour tous ceuxRecyclerView
qui utilisentLinearLayoutManager
ouGridLayoutManager
avec un simple appel de méthode.la source
Je vais vous montrer comment créer un en-tête avec des articles dans une vue Recycler.
Étape 1- Ajoutez une dépendance dans votre fichier Gradle.
Cardview est utilisé à des fins de décoration.
Étape 2 - Créez trois fichiers xml. Un pour l'activité principale. Deuxièmement pour la disposition des en-têtes. Troisième pour la disposition des éléments de liste.
activity_main.xml
header.xml
list.xml
Étape 3- Créez trois classes de bean.
Header.java
ContentItem.java
ListItem.java
Étape 4 - Créez un adaptateur nommé MyRecyclerAdapter.java
Étape 5 - Dans MainActivity, ajoutez le code suivant:
La fonction getList () génère dynamiquement les données des en-têtes et des éléments de liste.
la source
Vous pouvez y parvenir en utilisant la bibliothèque SectionedRecyclerViewAdapter , elle a le concept de "Sections", où quelle section a un en-tête, un pied de page et un contenu (liste d'éléments). Dans votre cas, il se peut que vous n'ayez besoin que d'une section, mais vous pouvez en avoir plusieurs:
1) Créez une classe Section personnalisée:
2) Créez un ViewHolder personnalisé pour les éléments:
3) Configurez votre ReclyclerView avec le SectionedRecyclerViewAdapter
la source
Vous pouvez simplement placer votre en-tête et votre RecyclerView dans un NestedScrollView:
Pour que le défilement fonctionne correctement, vous devez désactiver le défilement imbriqué sur votre RecyclerView:
la source
L'API native n'a pas une telle fonctionnalité "addHeader", mais a le concept "addItem".
J'ai pu inclure cette fonctionnalité spécifique des en-têtes et des extensions pour les pieds de page également dans mon projet FlexibleAdapter . Je l'ai appelé en -têtes et pieds de page défilables .
Voici comment ils fonctionnent:
Les en-têtes et pieds de page défilables sont des éléments spéciaux qui défilent avec tous les autres, mais ils n'appartiennent pas aux éléments principaux (éléments commerciaux) et ils sont toujours gérés par l'adaptateur à côté des éléments principaux. Ces éléments sont constamment placés aux première et dernière positions.
Il y a beaucoup à dire à leur sujet, mieux vaut lire la page wiki détaillée .
De plus, le FlexibleAdapter vous permet de créer des en-têtes / sections, vous pouvez également les coller et des dizaines d'autres fonctionnalités comme des éléments extensibles, un défilement sans fin, des extensions d'interface utilisateur, etc. dans une seule bibliothèque!
la source
Sur la base de ce message , 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 de mettre en œuvre un StaggeredGridLayoutManager à partir de zéro (ni même de l'étendre).
Je le teste encore, mais vous pouvez l'essayer si vous le souhaitez. Veuillez me faire savoir si vous rencontrez des problèmes avec celui-ci.
la source
Il existe une autre solution qui couvre tous les cas d'utilisation ci-dessus: CompoundAdapter: https://github.com/negusoft/CompoundAdapter-android
Vous pouvez créer un groupe d'adaptateurs qui contient votre adaptateur tel quel, ainsi qu'un adaptateur avec un seul élément pour représenter l'en-tête. Le code est simple et lisible:
AdapterGroup permet également l'imbrication, donc pour un adaptateur avec des sections, vous pouvez créer un AdapterGroup par section. Ensuite, placez toutes les sections dans un AdapterGroup racine.
la source
HeaderView dépend du LayoutManager. Aucun des LayoutManagers par défaut ne le prend en charge et ne le fera probablement pas. HeaderView dans ListView crée beaucoup de complexité sans aucun avantage significatif.
Je suggère de créer une classe d'adaptateur de base qui ajoute des éléments pour les en-têtes, le cas échéant. N'oubliez pas de remplacer les méthodes notify * pour les compenser correctement selon que l'en-tête est présent ou non.
la source
ListView.addHeaderView
ou la réponse à cette question.Après - Remplacez la méthode getItemViewTpe *** Plus important
méthode onCreateViewHolder
méthode onBindViewHolder
in finish implémente la classe ViewHolders statique
la source
ici une décoration pour le recyclage
la source
J'ai fait une implémentation basée sur celle de @ hister à mes fins personnelles, mais en utilisant l'héritage.
Je cache les mécanismes de détails d'implémentation (comme ajouter 1 à
itemCount
, soustraire 1 àposition
) dans une super classe abstraiteHeadingableRecycleAdapter
, en implémentant les méthodes requises de Adapter likeonBindViewHolder
,getItemViewType
etgetItemCount
, en rendant ces méthodes finales et en fournissant de nouvelles méthodes avec une logique cachée au client:onAddViewHolder(RecyclerView.ViewHolder holder, int position)
,onCreateViewHolder(ViewGroup parent)
,itemCount()
Voici la
HeadingableRecycleAdapter
classe et un client. J'ai laissé la disposition de l'en-tête un peu codée en dur car elle correspond à mes besoins.la source
Peut-être envelopper l'en-tête et la vue d'ensemble du recyclage dans une présentation de coordinateur :
la source
Http://alexzh.com/tutorials/multiple-row-layouts-using-recyclerview/ vous aidera probablement . Il utilise uniquement RecyclerView et CardView. Voici un adaptateur:
Et voici une entité:
la source
vous pouvez créer addHeaderView et utiliser
adapter.addHeaderView(View)
.Ce code crée le
addHeaderView
pour plus d'un en-tête. les en-têtes doivent avoir:android:layout_height="wrap_content"
la source
Cela fait quelques années, mais juste au cas où quelqu'un lirait ça plus tard ...
Le problème est dans la déclaration constante:
Si vous les déclarez tous les deux à zéro, vous obtiendrez toujours zéro!
la source
J'ai mis en œuvre la même approche que celle proposée par la réponse EC84B4 , mais j'ai résumé RecycleViewAdapter et le rendre facilement réutilisable au moyen d'interfaces.
Donc, pour utiliser mon approche, vous devez ajouter les classes de base et les interfaces suivantes à votre projet:
1) Interface fournissant des données pour l'adaptateur (collecte de type générique T et paramètres supplémentaires (si nécessaire) de type générique P)
2) Usine de reliure de vos articles (en-tête / article):
3) Usine pour viewHolders (en-tête / articles):
4) Classe de base pour l'adaptateur avec en-tête:
Exemple d'utilisation :
1) Implémentation d'IRecycleViewListHolder:
2) Implémentation IViewHolderBinderFactory:
3) Implémentation IViewHolderFactory:
4) Adaptateur dérivant
5) Instancier la classe d'adaptateur:
PS : AssetItemViewHolder, AssetBasedListItemBinding, etc. mes propres structures d'application qui devraient être échangées par les vôtres, à vos propres fins.
la source