Ich suche nach einem Äquivalent zu addHeaderView für eine Recycler-Ansicht. Grundsätzlich möchte ich, dass ein Bild mit 2 Schaltflächen als Kopfzeile zur Listenansicht hinzugefügt wird. Gibt es eine andere Möglichkeit, einer Recycler-Ansicht eine Header-Ansicht hinzuzufügen? Ein Beispiel für eine Anleitung wäre hilfreich
EDIT 2 (Fragmentlayouts hinzugefügt):
Nach dem Hinzufügen von Protokollanweisungen scheint getViewType immer nur die Position 0 zu erhalten. Dies führt dazu, dass onCreateView nur das eine Layout lädt:
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
Der Fragmentübergang zum Laden des CommentFragments:
@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 des Fragments:
@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;
}
Das Fragment mit der Recyclingansicht:
<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>
Das Zeilenlayout der Kommentare:
<?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>
Der Header
<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>
Der Adaptercode (danke an hister für den Einstieg):
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);
}
}
}
Mit dem obigen Code wird nur das Header-Layout angezeigt, da viewType immer 0 ist. Es sieht so aus . Wenn ich das andere Layout erzwingen sieht es aus wie diese :
quelle
Antworten:
Es gibt keinen einfachen Weg,
listview.addHeaderView()
aber Sie können dies erreichen, indem Sie Ihrem Adapter einen Typ für den Header hinzufügen.Hier ist ein Beispiel
Link zum Kern -> hier
quelle
private String getItem(int position) { return data[position + 1]; }
Verursacht eine NPE. Da unsere Position aufgrund des Headers um eins erhöht wurde, müssen wir 1 subtrahieren, um das richtige Element aus unseren Daten zu erhalten [].private String getItem(int position) { return data[position - 1]; }
setSpanSizeLookup
für hinzufügenGridLayoutManager
, so dass Ihr Header alle Spalten nimmtEinfach und wiederverwendbar
ItemDecoration
Statische Header können einfach mit
ItemDecoration
und ohne weitere Änderungen hinzugefügt werden .Die Dekoration ist auch wiederverwendbar, da weder der Adapter noch der Adapter geändert werden müssen
RecyclerView
.Für den unten angegebenen Beispielcode muss eine Ansicht oben hinzugefügt werden, die wie alles andere einfach aufgeblasen werden kann. Es kann so aussehen:
Warum statisch ?
Wenn Sie nur Text und Bilder anzeigen müssen, ist diese Lösung genau das Richtige für Sie. Es gibt keine Möglichkeit für Benutzerinteraktionen wie Schaltflächen oder Pager anzeigen, da sie nur ganz oben auf Ihrer Liste angezeigt werden.
Leere Listenbehandlung
Wenn keine Ansicht zum Dekorieren vorhanden ist, wird die Dekoration nicht gezeichnet. Sie müssen immer noch selbst eine leere Liste bearbeiten. (Eine mögliche Problemumgehung besteht darin, dem Adapter ein Dummy-Element hinzuzufügen.)
Der Code
Den vollständigen Quellcode finden Sie hier auf GitHub, einschließlich a
Builder
, um bei der Initialisierung des Dekorators zu helfen, oder verwenden Sie einfach den folgenden Code und geben Sie Ihre eigenen Werte an den Konstruktor weiter.Bitte stellen Sie sicher, dass Sie eine korrekte
layout_height
Ansicht für Ihre Ansicht festlegen . zBmatch_parent
funktioniert möglicherweise nicht richtig.Bitte beachten Sie: Das GitHub-Projekt ist mein persönlicher Spielplatz. Es ist nicht gründlich getestet, weshalb keine Bibliothek gibt es noch .
Was tut es?
Eine
ItemDecoration
zusätzliche Zeichnung zu einem Element einer Liste. In diesem Fall wird eine Dekoration oben auf den ersten Artikel gezeichnet.Die Ansicht wird gemessen und angelegt, dann wird sie oben auf das erste Element gezeichnet. Wenn ein Parallaxeeffekt hinzugefügt wird, wird dieser ebenfalls an die richtigen Grenzen gekürzt.
quelle
Fühlen Sie sich frei, meine Bibliothek zu nutzen, die hier verfügbar ist .
Hiermit können Sie einen Header
View
für jeden erstellenRecyclerView
, derLinearLayoutManager
oderGridLayoutManager
nur einen einfachen Methodenaufruf verwendet.quelle
Zeigen Sie, wie Sie in einer Recycler-Ansicht eine Kopfzeile mit Elementen erstellen.
Schritt 1 - Fügen Sie Ihrer Gradle-Datei eine Abhängigkeit hinzu.
Cardview wird zu Dekorationszwecken verwendet.
Schritt 2: Erstellen Sie drei XML-Dateien. Eine für die Hauptaktivität. Zweitens für das Header-Layout. Drittens für das Listenelement-Layout.
activity_main.xml
header.xml
list.xml
Schritt 3 - Erstellen Sie drei Bean-Klassen.
Header.java
ContentItem.java
ListItem.java
Schritt 4: Erstellen Sie einen Adapter mit dem Namen MyRecyclerAdapter.java
Schritt 5- Fügen Sie in MainActivity den folgenden Code hinzu:
Die Funktion getList () generiert dynamisch die Daten für die Header und für Listenelemente.
quelle
Sie können dies mit der Bibliothek SectionedRecyclerViewAdapter erreichen . Sie hat das Konzept "Abschnitte", wobei dieser Abschnitt eine Kopfzeile, eine Fußzeile und einen Inhalt (Liste der Elemente) enthält. In Ihrem Fall benötigen Sie möglicherweise nur einen Abschnitt, aber Sie können viele haben:
1) Erstellen Sie eine benutzerdefinierte Abschnittsklasse:
2) Erstellen Sie einen benutzerdefinierten ViewHolder für die Elemente:
3) Richten Sie Ihre ReclyclerView mit dem SectionedRecyclerViewAdapter ein
quelle
Sie können einfach Ihren Header und Ihre RecyclerView in einer NestedScrollView platzieren:
Damit das Scrollen ordnungsgemäß funktioniert, müssen Sie das verschachtelte Scrollen in Ihrem RecyclerView deaktivieren:
quelle
Die native API verfügt nicht über eine solche Funktion "addHeader", sondern über das Konzept "addItem".
Ich konnte diese spezielle Funktion von Kopf- und Fußzeilen auch in mein FlexibleAdapter- Projekt aufnehmen. Ich nannte es scrollbare Kopf- und Fußzeilen .
Hier, wie sie funktionieren:
Bildlaufbare Kopf- und Fußzeilen sind spezielle Elemente, die zusammen mit allen anderen Elementen gescrollt werden. Sie gehören jedoch nicht zu den Hauptelementen (Geschäftselementen) und werden immer vom Adapter neben den Hauptelementen verwaltet. Diese Elemente befinden sich dauerhaft an der ersten und letzten Position.
Es gibt viel zu sagen, besser die detaillierte Wiki-Seite zu lesen .
Darüber hinaus können Sie mit dem FlexibleAdapter Überschriften / Abschnitte erstellen. Außerdem können Sie sie klebrig machen und viele andere Funktionen wie erweiterbare Elemente, endloses Scrollen, UI-Erweiterungen usw. in einer Bibliothek!
quelle
Basierend auf diesem Beitrag habe ich eine Unterklasse von RecyclerView.Adapter erstellt, die eine beliebige Anzahl von Kopf- und Fußzeilen unterstützt.
https://gist.github.com/mheras/0908873267def75dc746
Obwohl es eine Lösung zu sein scheint, denke ich auch, dass dieses Ding vom LayoutManager verwaltet werden sollte. Leider brauche ich es jetzt und ich habe keine Zeit, einen StaggeredGridLayoutManager von Grund auf neu zu implementieren (oder sogar zu erweitern).
Ich teste es immer noch, aber Sie können es ausprobieren, wenn Sie wollen. Bitte lassen Sie mich wissen, wenn Sie Probleme damit haben.
quelle
Es gibt eine weitere Lösung, die alle oben genannten Anwendungsfälle abdeckt: CompoundAdapter: https://github.com/negusoft/CompoundAdapter-android
Sie können eine Adaptergruppe erstellen, die Ihren Adapter unverändert enthält, zusammen mit einem Adapter mit einem einzelnen Element, das den Header darstellt. Der Code ist einfach und lesbar:
AdapterGroup ermöglicht auch das Verschachteln. Für einen Adapter mit Abschnitten können Sie daher eine AdapterGroup pro Abschnitt erstellen. Fügen Sie dann alle Abschnitte in eine Root-Adaptergruppe ein.
quelle
HeaderView hängt vom LayoutManager ab. Keiner der Standard-LayoutManager unterstützt dies und wird dies wahrscheinlich nicht tun. HeaderView in ListView schafft viel Komplexität ohne nennenswerten Nutzen.
Ich würde vorschlagen, eine Basisadapterklasse zu erstellen, die Elemente für Header hinzufügt, falls vorhanden. Vergessen Sie nicht, notify * -Methoden zu überschreiben, um sie richtig zu versetzen, je nachdem, ob ein Header vorhanden ist oder nicht.
quelle
ListView.addHeaderView
die Antwort auf diese Frage.After - Überschreiben Sie die Methode getItemViewTpe *** Wichtiger
Methode onCreateViewHolder
Methode onBindViewHolder
In Finish wird die ViewHolders-Klasse static implementiert
quelle
hier einige artikeldekoration für recyclerview
quelle
Ich habe eine Implementierung basierend auf @ hister's gemacht für meine persönlichen Zwecke erstellt, aber unter Verwendung der Vererbung.
Ich verstecke die Mechanismen Implementierungsdetails (wie Add 1 bis
itemCount
subtrahieren 1 vonposition
) in einer abstrakten SuperklasseHeadingableRecycleAdapter
, die von erforderlichen Methoden von Adapter Implementierung wieonBindViewHolder
,getItemViewType
undgetItemCount
, was das Verfahren endgültig und neue Methoden mit versteckter Logik - Client bereitstellt:onAddViewHolder(RecyclerView.ViewHolder holder, int position)
,onCreateViewHolder(ViewGroup parent)
,itemCount()
Hier sind die
HeadingableRecycleAdapter
Klasse und ein Client. Ich habe das Header-Layout etwas fest codiert, weil es meinen Anforderungen entspricht.quelle
Vielleicht packen Sie Header und Recyclerview in ein Koordinatorlayout :
quelle
Wahrscheinlich hilft http://alexzh.com/tutorials/multiple-row-layouts-using-recyclerview/ . Es werden nur RecyclerView und CardView verwendet. Hier ist ein Adapter:
Und hier ist eine Entität:
quelle
Sie können addHeaderView erstellen und verwenden
adapter.addHeaderView(View)
.Dieser Code erstellt den
addHeaderView
für mehr als einen Header. Die Header sollten haben:android:layout_height="wrap_content"
quelle
Es ist ein paar Jahre her, aber nur für den Fall, dass jemand dies später liest ...
Das Problem liegt in der ständigen Deklaration:
Wenn Sie beide als Null deklarieren, erhalten Sie immer Null!
quelle
Ich habe den gleichen von EC84B4 vorgeschlagenen Ansatz umgesetzt Antwort , aber ich habe RecycleViewAdapter abstrahiert und ihn mithilfe von Schnittstellen leicht resuierbar gemacht.
Um meinen Ansatz zu verwenden, sollten Sie Ihrem Projekt folgende Basisklassen und Schnittstellen hinzufügen:
1) Schnittstelle, die Daten für den Adapter bereitstellt (Sammlung des generischen Typs T und zusätzliche Parameter (falls erforderlich) des generischen Typs P)
2) Fabrik zum Binden Ihrer Artikel (Header / Artikel):
3) Factory für viewHolders (Header / Elemente):
4) Basisklasse für Adapter mit Header:
Anwendungsbeispiel :
1) Implementierung von IRecycleViewListHolder:
2) IViewHolderBinderFactory-Implementierung:
3) IViewHolderFactory-Implementierung:
4) Adapter ableiten
5) Adapterklasse instanziieren:
PS : AssetItemViewHolder, AssetBasedListItemBinding usw. Meine Anwendung besitzt Strukturen, die von Ihnen für Ihre eigenen Zwecke ausgetauscht werden sollten.
quelle