Ich habe einen Moment lang RecyclerView
erfolglos versucht, einen Header zu einem hinzuzufügen .
Das habe ich bisher bekommen:
@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);
...
}
Das LayoutManager
scheint das Objekt zu sein, das die Disposition der RecyclerView
Gegenstände handhabt. Da ich keine finden konnte , addHeaderView(View view)
Verfahren, entschied ich mich mit dem Thema LayoutManager
‚s addView(View view, int position)
Methode und meine Kopfansicht in der ersten Position als Kopf zu handeln hinzuzufügen.
Und hier wird es hässlicher:
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)
Nachdem ich mehrere NullPointerExceptions
Versuche unternommen hatte, die addView(View view)
zu verschiedenen Zeitpunkten der Aktivitätserstellung aufzurufen (ich habe auch versucht, die Ansicht hinzuzufügen, sobald alles eingerichtet ist, sogar die Daten des Adapters), wurde mir klar, dass ich keine Ahnung habe, ob dies der richtige Weg ist (und das auch) sieht nicht so aus).
PS: Auch eine Lösung, die das GridLayoutManager
zusätzlich zum bewältigen könnte , LinearLayoutManager
wäre sehr dankbar!
quelle
Antworten:
Ich musste eine Fußzeile zu meiner hinzufügen
RecyclerView
und hier teile ich mein Code-Snippet, da ich dachte, dass es nützlich sein könnte. Bitte überprüfen Sie die Kommentare im Code, um den Gesamtfluss besser zu verstehen.Das obige Code-Snippet fügt der Fußzeile eine Fußzeile hinzu
RecyclerView
. Sie können dieses GitHub-Repository überprüfen, um die Implementierung des Hinzufügens von Kopf- und Fußzeilen zu überprüfen.quelle
RecyclerView
Daten dynamisch füllen können. Sie können jedes Ihrer Elemente steuernRecyclerView
. Bitte schauen Sie im Code-Abschnitt nach einem Arbeitsprojekt. Hoffe es könnte helfen. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Geben Sie den Ansichtstyp des Elements zum Zwecke des Ansichtsrecyclings an Position zurück. Die Standardimplementierung dieser Methode gibt 0 zurück, wobei ein einzelner Ansichtstyp für den Adapter angenommen wird. Im Gegensatz zuListView
Adaptern müssen Typen nicht zusammenhängend sein. Erwägen Sie die Verwendung von ID-Ressourcen, um Elementansichtstypen eindeutig zu identifizieren. - Aus der Dokumentation. developer.android.com/reference/android/support/v7/widget/…Sehr einfach zu lösen !!
Ich mag die Idee nicht, Logik im Adapter als einen anderen Ansichtstyp zu haben, da jedes Mal nach dem Ansichtstyp gesucht wird, bevor die Ansicht zurückgegeben wird. Die folgende Lösung vermeidet zusätzliche Überprüfungen.
Fügen Sie einfach die LinearLayout-Kopfansicht (vertikal) + die Recyclingansicht + die Fußzeile in android.support.v4.widget.NestedScrollView hinzu .
Überprüfen Sie dies heraus:
Fügen Sie diese Codezeile für einen reibungslosen Bildlauf hinzu
Dadurch geht die gesamte Leistung des Wohnmobils verloren, und das Wohnmobil versucht, alle Ansichtsinhaber unabhängig
layout_height
vom Wohnmobil auszulegenEmpfohlen für kleine Listen wie Navigationsschubladen oder Einstellungen usw.
quelle
RecyclerView
verlieren - Sie verlieren das eigentliche Recycling und die damit verbundene Optimierung.Ich hatte das gleiche Problem mit Lollipop und habe zwei Ansätze zum Umwickeln des
Recyclerview
Adapters entwickelt. Eines ist ziemlich einfach zu bedienen, aber ich bin mir nicht sicher, wie es sich bei einem sich ändernden Datensatz verhalten wird. Weil es Ihren Adapter umschließt und Sie sicherstellen müssen, dass Sie Methoden wienotifyDataSetChanged
auf dem richtigen Adapterobjekt aufrufen .Der andere sollte solche Probleme nicht haben. Lassen Sie einfach Ihren regulären Adapter die Klasse erweitern, implementieren Sie die abstrakten Methoden und Sie sollten bereit sein. Und hier sind sie:
Kern
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Feedback und Gabeln geschätzt. Ich werde es selbst nutzen
HeaderRecyclerViewAdapterV2
und die Änderungen in Zukunft weiterentwickeln, testen und veröffentlichen.EDIT : @OvidiuLatcu Ja, ich hatte einige Probleme. Eigentlich habe ich aufgehört, den Header implizit um zu versetzen,
position - (useHeader() ? 1 : 0)
und stattdessen eine öffentliche Methodeint offsetPosition(int position)
dafür erstellt. Denn wenn Sie eineOnItemTouchListener
auf Recyclerview setzen, können Sie die Berührung abfangen, die x-, y-Koordinaten der Berührung abrufen , die entsprechende untergeordnete Ansicht finden und dann anrufen,recyclerView.getChildPosition(...)
und Sie erhalten immer die nicht versetzte Position im Adapter! Dies ist ein Mangel im RecyclerView-Code. Ich sehe keine einfache Methode, um dies zu überwinden. Aus diesem Grund versetze ich jetzt die Positionen explizit, wenn ich muss, durch meinen eigenen Code.quelle
Ich habe dies nicht versucht, aber ich würde einfach 1 (oder 2, wenn Sie sowohl eine Kopf- als auch eine Fußzeile möchten) zu der von getItemCount in Ihrem Adapter zurückgegebenen Ganzzahl hinzufügen. Sie können dann
getItemViewType
Ihren Adapter überschreiben , um eine andere Ganzzahl zurückzugeben, wenni==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
Anschließend wird die von Ihnen zurückgegebene Ganzzahl übergebengetItemViewType
, sodass Sie den Ansichtsinhaber für die Header-Ansicht anders erstellen oder konfigurieren können: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , int)Vergessen Sie nicht, eine von der an übergebenen Positionszahl zu subtrahieren
bindViewHolder
.quelle
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(esRecyclerView
gibt keinegetViewTypeCount()
Methode). Andererseits stimme ich @IZI_Shadow_IZI zu, ich habe wirklich das Gefühl, dass der LayoutManager derjenige sein sollte, der diese Art von Dingen handhabt. Irgendeine andere Idee?Sie können diese GitHub- Bibliothek verwenden, um auf einfachste Weise Kopf- und / oder Fußzeilen in Ihre RecyclerView einzufügen .
Sie müssen Ihrem Projekt eine HFRecyclerView- Bibliothek hinzufügen, oder Sie können sie auch aus Gradle herunterladen :
Dies ist ein Ergebnis im Bild:
BEARBEITEN:
Wenn Sie mit dieser Bibliothek nur einen Rand oben und / oder unten hinzufügen möchten: SimpleItemDecoration :
quelle
Am Ende habe ich meinen eigenen Adapter implementiert, um jeden anderen Adapter zu verpacken und Methoden zum Hinzufügen von Kopf- und Fußzeilenansichten bereitzustellen.
Hier wurde ein Kernstück erstellt: HeaderViewRecyclerAdapter.java
Die Hauptfunktion, die ich wollte, war eine ähnliche Oberfläche wie eine ListView, daher wollte ich die Ansichten in meinem Fragment aufblasen und zur hinzufügen können
RecyclerView
InonCreateView
. Dazu erstellen Sie eineHeaderViewRecyclerAdapter
Übergabe des zu verpackenden Adapters und rufen Ihre aufgeblasenen Ansichten aufaddHeaderView
undaddFooterView
übergeben sie. Stellen Sie dann dieHeaderViewRecyclerAdapter
Instanz als Adapter auf dem einRecyclerView
.Eine zusätzliche Anforderung war, dass ich in der Lage sein musste, Adapter einfach auszutauschen, während die Kopf- und Fußzeilen beibehalten wurden. Ich wollte nicht mehrere Adapter mit mehreren Instanzen dieser Kopf- und Fußzeilen haben. Sie können also anrufen
setAdapter
, um den umschlossenen Adapter zu ändern, wobei die Kopf- und Fußzeilen intakt bleibenRecyclerView
über die Änderung informiert werden.quelle
Mein "halte es einfach dumm" Weg ... es verschwendet einige Ressourcen, ich weiß, aber es ist mir egal, da mein Code einfach bleibt, also ... 1) füge Fußzeile mit Sichtbarkeit GONE zu deinem item_layout hinzu
2) Setzen Sie es dann auf dem letzten Element sichtbar
Machen Sie das Gegenteil für den Header
quelle
Basierend auf der Lösung von @ seb 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 möchten. Bitte lassen Sie mich wissen, wenn Sie Probleme damit haben.
quelle
Sie können viewtype verwenden, um dieses Problem zu lösen. Hier ist meine Demo: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
Sie können einen Anzeigemodus für die Recycler-Ansicht definieren:
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. Überschreiben Sie die getItemViewType-Motte
3. Überschreiben Sie die Methode getItemCount
4. Überschreiben Sie die onCreateViewHolder-Methode. Erstellen Sie einen Ansichtshalter mit viewType
5.Überschreiben Sie die onBindViewHolder-Methode. Daten nach viewType binden
quelle
Mit der Bibliothek SectionedRecyclerViewAdapter können Sie Ihre Elemente in Abschnitte gruppieren und jedem Abschnitt eine Kopfzeile hinzufügen, wie in der Abbildung unten dargestellt:
Zuerst erstellen Sie Ihre Abschnittsklasse:
Anschließend richten Sie die RecyclerView mit Ihren Abschnitten ein und ändern die SpanSize der Header mit einem GridLayoutManager:
quelle
Ich weiß, dass ich zu spät komme, aber erst kürzlich konnte ich einen solchen "addHeader" für den Adapter implementieren. In meinem FlexibleAdapter- Projekt können Sie
setHeader
ein Sectionable- Element aufrufen und dann aufrufenshowAllHeaders
. Wenn Sie nur 1 Kopfzeile benötigen, sollte das erste Element die Kopfzeile haben. Wenn Sie dieses Element löschen, wird der Header automatisch mit dem nächsten verknüpft.Fußzeilen sind leider (noch) nicht abgedeckt.
Mit dem FlexibleAdapter können Sie viel mehr als nur Kopfzeilen / Abschnitte erstellen. Sie sollten wirklich einen Blick darauf werfen: https://github.com/davideas/FlexibleAdapter .
quelle
Ich würde nur eine Alternative zu all diesen HeaderRecyclerViewAdapter-Implementierungen hinzufügen. CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
Dies ist ein flexiblerer Ansatz, da Sie aus Adaptern eine Adaptergruppe erstellen können. Verwenden Sie für das Header-Beispiel Ihren Adapter so wie er ist, zusammen mit einem Adapter, der ein Element für den Header enthält:
Es ist ziemlich einfach und lesbar. Sie können komplexere Adapter einfach nach demselben Prinzip implementieren.
quelle