Est-il un addHeaderView équivalent pour RecyclerView?
Je suis à la recherche d'un équivalent de addHeaderView pour un recycleur de vue. Fondamentalement, je veux avoir une image avec 2 boutons-être ajouté comme en-tête de la liste. Est-il un autre moyen d'ajouter un en-tête de la vue à un recycleur de vue? Un exemple pour l'orientation serait utile
EDIT 2 (ajouté fragment de mises en page):
Après l'ajout du journal des déclarations, il semble que getViewType ne reçoit qu'une position de 0. Cela conduit à onCreateView que le chargement de la mise en page:
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
Le fragment de transition 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();
}
}
Le Fragment de la onCreateView:
@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 le 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 ligne commentaires mise en page:
<?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 d'Adaptateur (grâce à hister de m'avoir commencé):
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);
}
}
}
L'aide du code ci-dessus, seule la mise en page d'en-tête est affiché comme viewType est toujours 0. Il ressemble à cette. Si je force la disposition d'autres il ressemble cette:
- double possible de Android 5.0 - Ajouter un en-tête/pied de page à une RecyclerView
- Comme c'est un doublon de la question here, j'ai posté ma réponse il:
- Une solution élégante: stackoverflow.com/questions/33579800/...
Vous devez vous connecter pour publier un commentaire.
Il n'y a pas un moyen facile comme
listview.addHeaderView()
mais vous pouvez l'obtenir par l'ajout d'un type de votre carte d'en-tête.Voici un exemple
lien vers gist -> ici
private String getItem(int position) { return data[position + 1]; }
Provoque une NPE. Depuis notre position a été augmenté par un, en raison de l'en-tête, nous devons soustraire 1 pour obtenir le bon produit à partir de nos données[].private String getItem(int position) { return data[position - 1]; }
setSpanSizeLookup
pourGridLayoutManager
, de sorte que votre tête va prendre toutes les colonnesviewType
est 0 ou 1? Quelque chose que je suis vraiment étonné.Facile et réutilisables
ItemDecoration
Statique en-têtes peuvent facilement être ajoutées avec un
ItemDecoration
et sans changement.La décoration est également réutilisable car il n'est pas nécessaire de modifier la carte ou le
RecyclerView
à tous.L'exemple de code fourni ci-dessous nécessitent une vue d'ajouter vers le haut qui peut simplement être gonflé comme tout le reste. Il peut ressembler à ceci:
Pourquoi statique?
Si vous avez juste à afficher le texte et les images de cette solution est pour vous—il n'y a pas de possibilité pour l'utilisateur d'interagir, comme les boutons ou la vue téléavertisseurs, car il va juste être tiré vers le haut de votre liste.
Vide de la gestion des listes
Si il n'est pas tenu de les décorer, la décoration ne sera pas affichée. Vous allez toujours avoir à gérer une liste vide vous-même. (Une solution possible serait d'ajouter un mannequin élément de la carte.)
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 fournir vos propres valeurs pour le constructeur.Assurez-vous de définir une bonne
layout_height
pour votre point de vue. par exemple,match_parent
peut ne pas fonctionner correctement.Veuillez noter: Le projet GitHub est mon terrain de jeu personnel. Il n'est pas thorougly testé, c'est pourquoi il n'y a pas de bibliothèque encore.
Que fait-il?
Un
ItemDecoration
supplémentaire de dessin à un élément d'une liste. Dans ce cas, une décoration est aspiré vers le haut du premier élément.Le point de vue qui est mesuré et mis, alors il est aspiré vers le haut du premier élément. Si un effet de parallaxe est ajouté, il sera également attaché à la bornes correctes.
fragmentManager
magique 🙂 Avec quelques modifications mineures qu'il devrait être possible, je ne sais pas comment bien le haut de ma têteLinearLayoutManager.HORIZONTAL
et le premier élément (pas d'en-tête) est en dessous de l'en-tête et le reste des éléments sont sur le côté droit de la tête.N'hésitez pas à utiliser ma bibliothèque, disponible ici.
Il vous permet de créer en-tête
View
pour toutRecyclerView
qui utiliseLinearLayoutManager
ouGridLayoutManager
avec juste un simple appel de méthode.Va vous montrer pour faire de l'en-tête avec des éléments dans un Recycleur de vue.
Étape 1: Ajout de la dépendance dans votre gradle fichier.
Cardview est utilisé pour la décoration de but.
Etape 2 - Faire des trois fichiers xml.
Une activité principale.Deuxième pour la mise en page d'en-Tête.Troisième pour l'élément de la liste mise en page.
activity_main.xml
header.xml
list.xml
Étape 3 - Créer trois types de haricots.
Header.java
ContentItem.java
ListItem.java
Étape 4 - Créer un adaptateur nommé MyRecyclerAdapter.java
Étape 5-
Dans MainActivity ajoutez le code suivant:
La fonction getList() est de générer dynamiquement les données pour les en-têtes et des éléments de liste.
Vous pouvez la réaliser à l'aide de la bibliothèque SectionedRecyclerViewAdapter, c'est le concept de "Sections", où la Section qui contient un en-Tête, Pied de page et le Contenu (liste des articles). Dans votre cas, vous pourriez seulement besoin d'une Section, mais vous pouvez avoir beaucoup d':
1) Créer une Section personnalisée classe:
2) Créer un personnalisé ViewHolder pour les éléments:
3) configurer votre ReclyclerView avec le SectionedRecyclerViewAdapter
Vous pouvez simplement placer votre tête et votre RecyclerView dans un NestedScrollView:
Afin de faire défiler l'écran fonctionne correctement, vous devez désactiver imbriquée de défilement sur votre RecyclerView:
Basé sur ce post, j'ai créé une sous-classe de RecyclerView.L'adaptateur prend en charge un nombre arbitraire d'en-têtes et pieds de page.
https://gist.github.com/mheras/0908873267def75dc746
Bien qu'il semble être une solution, je pense aussi que cette chose doit être géré par le LayoutManager. Malheureusement, j'en ai besoin maintenant et je n'ai pas le temps de mettre en œuvre un StaggeredGridLayoutManager à partir de rien (ni même s'étendre de lui).
Je suis encore en test, mais vous pouvez l'essayer si vous le souhaitez. S'il vous plaît laissez-moi savoir si vous trouvez des problèmes avec elle.
API Native n'a pas de telles "addHeader", mais le concept de "addItem".
J'ai été en mesure d'inclure cette fonctionnalité spécifique des en-têtes et s'étend pour les pieds bien dans mon FlexibleAdapter projet. Je l'ai appelé Défilement des en-Têtes et Pieds de page.
Voici comment ils fonctionnent:
Défilement des en-Têtes et Pieds de page sont des objets spéciaux qui défilent le long avec tous les autres, mais ils ne sont pas appartient principaux éléments (objets) et ils sont toujours gérés par la carte à côté de la principale éléments. Ces éléments sont constamment situé au premier et dernier positions.
Il y a beaucoup à dire à leur sujet, il vaut mieux lire le détail page wiki.
En outre, le FlexibleAdapter vous permet de créer des en-têtes/sections, vous pouvez également avoir collant et des dizaines d'autres fonctionnalités comme extensible éléments, une infinité de défilement, des extensions d'INTERFACE etc... le tout dans une bibliothèque!
Il y a une solution qui couvre tous les cas d'utilisation ci-dessus: CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
Vous pouvez créer un AdapterGroup qui détient votre Carte, tel qu'il est, le long avec un adaptateur avec un seul élément à représenter l'en-tête. Le code est simple et lisible:
AdapterGroup permet de nidification trop, donc pour une carte avec des sections, vous pouvez créer un AdapterGroup par section. Ensuite, mettre tous les articles dans une racine AdapterGroup.
HeaderView dépend de la LayoutManager. Aucun défaut LayoutManagers en charge ce et probablement l'habitude. HeaderView dans ListView crée beaucoup de complexité, sans aucun avantage significatif.
Je suggère la création d'une base de l'adaptateur de classe qui ajoute des éléments pour les en-Têtes, si disponible. N'oubliez pas de remplacer informer* les moyens de les compenser correctement selon que l'en-tête est présent ou pas.
ListView.addHeaderView
ou la réponse à cette question.Après - Remplacer la méthode getItemViewTpe
***Plus Important
méthode onCreateViewHolder
méthode onBindViewHolder
en finition met en œuvre la ViewHolders classe statique
ici quelques itemdecoration pour recyclerview
J'ai fait une implémentation basée sur @hister de l' un pour mon usage personnel, mais l'utilisation de l'héritage.
- Je cacher les détails d'implémentation des mécanismes (comme ajouter 1 à
itemCount
, soustraire 1 deposition
), en résumé super classeHeadingableRecycleAdapter
, parla mise en œuvre de méthodes requises à partir de l'Adaptateur comme
onBindViewHolder
,getItemViewType
etgetItemCount
, faisant que les méthodes final, et en fournissant de nouvelles méthodes avec la logique cachée client:onAddViewHolder(RecyclerView.ViewHolder holder, int position)
,onCreateViewHolder(ViewGroup parent)
,itemCount()
Voici les
HeadingableRecycleAdapter
classe et un client. J'ai quitté l'en-tête de la mise en page un peu codé en dur, car il correspond à mes besoins.Probablement http://alexzh.com/tutorials/multiple-row-layouts-using-recyclerview/ aidera. Il utilise seulement RecyclerView et CardView.
Voici une carte:
Et voici une entité:
vous pouvez créer addHeaderView et l'utilisation
adapter.addHeaderView(View)
.Ce code de construire le
addHeaderView
pour plus d'un en-tête.les en-têtes doivent avoir:
android:layout_height="wrap_content"
Peut-être enveloppement d'en-tête et recyclerview dans un coordinatorlayout: