Saya menghabiskan waktu sejenak mencoba mencari cara untuk menambahkan header ke file RecyclerView
, tidak berhasil.
Inilah yang saya dapatkan sejauh ini:
@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);
...
}
The LayoutManager
tampaknya menjadi objek penanganan disposisi dari RecyclerView
item. Seperti yang saya tidak bisa menemukan addHeaderView(View view)
metode, saya memutuskan untuk pergi dengan LayoutManager
's addView(View view, int position)
metode dan menambah tampilan judul saya di posisi pertama untuk bertindak sebagai header.
Aa dan di sinilah segalanya menjadi lebih buruk:
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)
Setelah NullPointerExceptions
mencoba beberapa kali untuk memanggil addView(View view)
pada momen yang berbeda dari pembuatan Aktivitas (juga mencoba menambahkan tampilan setelah semuanya diatur, bahkan data Adaptor), saya menyadari bahwa saya tidak tahu apakah ini cara yang tepat untuk melakukannya (dan itu tidak terlihat).
PS: Juga, solusi yang bisa menangani GridLayoutManager
selain itu LinearLayoutManager
akan sangat dihargai!
sumber
Jawaban:
Saya harus menambahkan footer ke saya
RecyclerView
dan di sini saya membagikan cuplikan kode saya karena saya pikir itu mungkin berguna. Silakan periksa komentar di dalam kode untuk pemahaman yang lebih baik tentang aliran keseluruhan.Potongan kode di atas menambahkan footer ke
RecyclerView
. Anda dapat memeriksa repositori GitHub ini untuk memeriksa implementasi penambahan header dan footer.sumber
RecyclerView
secara dinamis. Anda dapat mengontrol setiap elemen AndaRecyclerView
. Silakan lihat bagian kode untuk proyek kerja. Semoga bisa membantu. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Kembalikan jenis tampilan item pada posisinya untuk tujuan daur ulang tampilan. Implementasi default metode ini mengembalikan 0, membuat asumsi tipe tampilan tunggal untuk adaptor. Tidak sepertiListView
adaptor, tipe tidak perlu bersebelahan. Pertimbangkan menggunakan sumber daya id untuk mengidentifikasi tipe tampilan item secara unik. - Dari dokumentasi. developer.android.com/reference/android/support/v7/widget/…Sangat mudah untuk dipecahkan !!
Saya tidak suka gagasan memiliki logika di dalam adaptor sebagai tipe tampilan yang berbeda karena setiap kali memeriksa tipe tampilan sebelum mengembalikan tampilan. Solusi di bawah ini menghindari pemeriksaan ekstra.
Cukup tambahkan tampilan header LinearLayout (vertikal) + tampilan recyclerview + footer di dalam android.support.v4.widget.NestedScrollView .
Lihat ini:
Tambahkan baris kode ini untuk pengguliran lancar
Ini akan kehilangan semua kinerja RV dan RV akan mencoba untuk menata semua pemegang tampilan terlepas
layout_height
dari RVDisarankan menggunakan untuk daftar ukuran kecil seperti laci Nav atau pengaturan dll.
sumber
RecyclerView
dihasilkan - Anda kehilangan daur ulang yang sebenarnya dan pengoptimalan yang dihasilkannya.Saya memiliki masalah yang sama di Lollipop dan membuat dua pendekatan untuk membungkus
Recyclerview
adaptor. Salah satunya cukup mudah digunakan, tetapi saya tidak yakin bagaimana perilakunya dengan kumpulan data yang berubah. Karena itu membungkus adaptor Anda dan Anda perlu memastikan diri Anda sendiri untuk memanggil metode sepertinotifyDataSetChanged
pada objek adaptor yang tepat.Yang lainnya seharusnya tidak memiliki masalah seperti itu. Biarkan adaptor reguler Anda memperluas kelas, terapkan metode abstrak dan Anda sudah siap. Dan inilah mereka:
inti
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Umpan balik dan garpu dihargai. Saya akan menggunakan
HeaderRecyclerViewAdapterV2
sendiri dan mengembangkan, menguji, dan memposting perubahan di masa mendatang.EDIT : @OvidiuLatcu Ya, saya punya beberapa masalah. Sebenarnya saya berhenti mengimbangi Header secara implisit dengan
position - (useHeader() ? 1 : 0)
dan sebagai gantinya membuat metode publikint offsetPosition(int position)
untuk itu. Karena jika Anda menyetelOnItemTouchListener
pada Recyclerview, Anda dapat mencegat sentuhan, mendapatkan koordinat x, y dari sentuhan tersebut, menemukan tampilan anak yang sesuai, lalu memanggilrecyclerView.getChildPosition(...)
dan Anda akan selalu mendapatkan posisi non-offset di adaptor! Ini adalah shortcomming di RecyclerView Code, saya tidak melihat metode yang mudah untuk mengatasinya. Inilah sebabnya mengapa saya sekarang mengimbangi posisi eksplisit ketika saya perlu dengan kode saya sendiri .sumber
Saya belum mencoba ini, tetapi saya hanya akan menambahkan 1 (atau 2, jika Anda menginginkan header dan footer) ke integer yang dikembalikan oleh getItemCount di adaptor Anda. Anda kemudian dapat mengganti
getItemViewType
adaptor Anda untuk mengembalikan bilangan bulat yang berbeda ketikai==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
kemudian diteruskan bilangan bulat yang Anda kembalikangetItemViewType
, memungkinkan Anda membuat atau mengonfigurasi view holder secara berbeda untuk tampilan header: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , int)Jangan lupa untuk mengurangi satu dari bilangan bulat posisi yang diteruskan
bindViewHolder
.sumber
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(RecyclerView
tidak memilikigetViewTypeCount()
metode). Di sisi lain, saya setuju dengan @IZI_Shadow_IZI, saya merasa LayoutManagerlah yang harus menangani hal-hal semacam ini. Ada ide lain?Anda dapat menggunakan pustaka GitHub ini yang memungkinkan untuk menambahkan Header dan / atau Footer di RecyclerView Anda dengan cara yang sesederhana mungkin.
Anda perlu menambahkan pustaka HFRecyclerView di proyek Anda atau Anda juga bisa mengambilnya dari Gradle:
Ini adalah hasil gambar:
EDIT:
Jika Anda hanya ingin menambahkan margin di bagian atas dan / atau bawah dengan library ini: SimpleItemDecoration :
sumber
Saya akhirnya menerapkan adaptor saya sendiri untuk membungkus adaptor lain dan menyediakan metode untuk menambahkan tampilan header dan footer.
Membuat intinya di sini: HeaderViewRecyclerAdapter.java
Fitur utama yang saya inginkan adalah antarmuka yang mirip dengan ListView, jadi saya ingin dapat memperbesar tampilan di Fragmen saya dan menambahkannya ke
RecyclerView
dalamonCreateView
. Ini dilakukan dengan membuatHeaderViewRecyclerAdapter
penerusan adaptor untuk dibungkus, dan memanggiladdHeaderView
sertaaddFooterView
meneruskan tampilan yang diluaskan. Kemudian setelHeaderViewRecyclerAdapter
instance sebagai adaptor padaRecyclerView
.Persyaratan tambahan adalah bahwa saya harus dapat dengan mudah menukar adaptor sambil mempertahankan header dan footer, saya tidak ingin memiliki banyak adaptor dengan banyak contoh header dan footer ini. Jadi, Anda dapat memanggil
setAdapter
untuk mengubah adaptor yang dibungkus dengan membiarkan header dan footer tetap utuh, denganRecyclerView
pemberitahuan tentang perubahan tersebut.sumber
cara saya "tetap sederhana, bodoh" ... itu menyia-nyiakan beberapa sumber daya, saya tahu, tetapi saya tidak peduli karena kode saya tetap sederhana jadi ... 1) tambahkan footer dengan visibilitas PERGI ke item_layout Anda
2) lalu atur agar terlihat di item terakhir
lakukan sebaliknya untuk header
sumber
Berdasarkan solusi @ seb, saya membuat subclass RecyclerView.Adapter yang mendukung sejumlah header dan footer.
https://gist.github.com/mheras/0908873267def75dc746
Meskipun tampaknya menjadi solusi, menurut saya hal ini juga harus dikelola oleh LayoutManager. Sayangnya, saya membutuhkannya sekarang dan saya tidak punya waktu untuk mengimplementasikan StaggeredGridLayoutManager dari awal (atau bahkan memperpanjangnya).
Saya masih mengujinya, tapi Anda bisa mencobanya jika mau. Beri tahu saya jika Anda menemukan masalah apa pun dengannya.
sumber
Anda dapat menggunakan viewtype untuk mengatasi masalah ini, berikut demo saya: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
Anda dapat menentukan beberapa mode tampilan tampilan daur ulang:
public int static final MODE_DATA = 0, MODE_LOADING = 1, MODE_ERROR = 2, MODE_EMPTY = 3, MODE_HEADER_VIEW = 4, MODE_FOOTER_VIEW = 5;
2. ganti mothod getItemViewType
3. ganti metode getItemCount
4. ganti metode onCreateViewHolder. buat view holder dengan viewType
5. Ganti metode onBindViewHolder. ikat data dengan viewType
sumber
Anda dapat menggunakan pustaka SectionedRecyclerViewAdapter untuk mengelompokkan item Anda dalam beberapa bagian dan menambahkan header ke setiap bagian, seperti pada gambar di bawah ini:
Pertama Anda membuat kelas bagian Anda:
Kemudian Anda menyiapkan RecyclerView dengan bagian Anda dan mengubah SpanSize header dengan GridLayoutManager:
sumber
Saya tahu saya datang terlambat, tetapi baru belakangan ini saya bisa menerapkan "addHeader" seperti itu ke Adaptor. Dalam saya FlexibleAdapter proyek Anda dapat memanggil
setHeader
pada Sectionable item, maka Anda meneleponshowAllHeaders
. Jika Anda hanya membutuhkan 1 header maka item pertama harus memiliki header. Jika Anda menghapus item ini, maka header secara otomatis ditautkan ke item berikutnya.Sayangnya footer belum tercakup (belum).
FlexibleAdapter memungkinkan Anda melakukan lebih dari sekadar membuat header / bagian. Anda benar-benar harus melihat: https://github.com/davideas/FlexibleAdapter .
sumber
Saya hanya akan menambahkan alternatif untuk semua implementasi HeaderRecyclerViewAdapter tersebut. CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
Ini adalah pendekatan yang lebih fleksibel, karena Anda dapat membuat AdapterGroup dari Adapters. Untuk contoh header, gunakan adaptor Anda apa adanya, bersama dengan adaptor yang berisi satu item untuk header:
Ini cukup sederhana dan mudah dibaca. Anda dapat menerapkan adaptor yang lebih kompleks dengan mudah menggunakan prinsip yang sama.
sumber
recyclerview:1.2.0
memperkenalkan kelas ConcatAdapter yang menggabungkan beberapa adaptor menjadi satu. Jadi memungkinkan untuk membuat adaptor header / footer terpisah dan menggunakannya kembali di beberapa daftar.Lihat artikel pengumuman . Ini berisi contoh bagaimana menampilkan kemajuan pemuatan di header dan footer menggunakan
ConcatAdapter
.Untuk saat saya memposting jawaban ini versi
1.2.0
library berada dalam tahap alpha, jadi api mungkin berubah. Anda dapat memeriksa statusnya di sini .sumber