Saya sedang menjelajah RecyclerView
dan saya terkejut melihat yang RecyclerView
tidak ada onItemClickListener()
.
Saya punya dua pertanyaan.
Pertanyaan utama
Saya ingin tahu mengapa Google dihapus onItemClickListener()
?
Apakah ada masalah kinerja atau hal lain?
Pertanyaan Sekunder
Saya memecahkan masalah saya dengan menulis onClick
di RecyclerView.Adapter
:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
Apakah ini ok / adakah cara yang lebih baik?
java
android
android-recyclerview
Tarun Varshney
sumber
sumber
QUESTION
Jawaban:
tl; dr 2016 Gunakan RxJava dan PublishSubject untuk mengekspos Observable untuk klik.
Pos Asli:
Sejak diperkenalkannya
ListView
,onItemClickListener
telah bermasalah. Saat Anda memiliki pendengar klik untuk salah satu elemen internal, callback tidak akan dipicu tetapi tidak diberitahukan atau didokumentasikan dengan baik (jika ada) sehingga ada banyak kebingungan dan pertanyaan SO tentang hal itu.Mengingat hal
RecyclerView
itu selangkah lebih maju dan tidak memiliki konsep baris / kolom, melainkan jumlah anak-anak yang ditata secara sewenang-wenang, mereka telah mendelegasikan onClick ke masing-masing dari mereka, atau untuk implementasi programmer.Pikirkan
Recyclerview
bukan sebagaiListView
pengganti 1: 1 tetapi lebih sebagai komponen yang lebih fleksibel untuk kasus penggunaan kompleks. Dan seperti yang Anda katakan, solusi Anda adalah apa yang diharapkan Google dari Anda. Sekarang Anda memiliki adaptor yang dapat mendelegasikan onClick ke antarmuka yang diteruskan pada konstruktor, yang merupakan pola yang benar untuk keduanyaListView
danRecyclerview
.dan kemudian pada adaptor Anda
Sekarang perhatikan potongan kode terakhir:
onCreateViewHolder(ViewGroup parent, int viewType)
tanda tangan sudah menyarankan jenis tampilan yang berbeda. Untuk masing-masing dari mereka Anda akan memerlukan penonton yang berbeda juga, dan selanjutnya masing-masing dari mereka dapat memiliki set klik berbeda. Atau Anda bisa membuat viewholder generik yang mengambil tampilan apa pun dan satuonClickListener
dan berlaku sesuai. Atau mendelegasikan satu tingkat ke orkestra sehingga beberapa fragmen / kegiatan memiliki daftar yang sama dengan perilaku klik yang berbeda. Sekali lagi, semua fleksibilitas ada di pihak Anda.Ini adalah komponen yang sangat dibutuhkan dan cukup dekat dengan apa implementasi dan peningkatan internal kami
ListView
sampai sekarang. Ada baiknya Google akhirnya mengakuinya.sumber
onBindViewHolder(holder, position)
, di mana info seharusnya diisi.getPosition()
sudah tidak digunakan lagi "Metode ini sudah usang karena artinya ambigu karena penanganan async * pada pembaruan adaptor. Silakan gunakan {@link #getLayoutPosition ()} atau * {@link #getAdapterPosition ()} tergantung pada kasus penggunaan Anda. "viewHolder.getPosition();
Mengapa RecyclerView tidak memiliki
onItemClickListener
Itu
RecyclerView
adalah kotak alat, berbeda dari yang lamaListView
ia kurang memiliki fitur dan fleksibilitas lebih. InionItemClickListener
bukan satu-satunya fitur yang dihapus dari ListView. Tetapi memiliki banyak pendengar dan metode untuk memperluas sesuai dengan keinginan Anda, itu jauh lebih kuat di tangan kanan;).Menurut pendapat saya fitur paling kompleks yang dihapus
RecyclerView
adalah Fast Scroll . Sebagian besar fitur lainnya dapat dengan mudah diimplementasikan kembali.Jika Anda ingin tahu fitur keren apa yang
RecyclerView
ditambahkan, baca jawaban ini untuk pertanyaan lain.Memori efisien - solusi jatuhkan untuk onItemClickListener
Solusi ini telah diusulkan oleh Hugo Visser , sebuah GDE Android, tepat setelah
RecyclerView
dirilis. Dia membuat kelas bebas lisensi tersedia bagi Anda untuk hanya memasukkan kode Anda dan menggunakannya.Ini menampilkan beberapa fleksibilitas yang diperkenalkan dengan
RecyclerView
memanfaatkanRecyclerView.OnChildAttachStateChangeListener
.Sunting 2019 : versi kotlin oleh saya, java one, dari Hugo Visser, disimpan di bawah
Kotlin / Jawa
Buat file
values/ids.xml
dan letakkan ini di dalamnya:kemudian tambahkan kode di bawah ini ke sumber Anda
Kotlin
Pemakaian:
(itu juga mendukung klik item panjang dan lihat di bawah untuk fitur lain yang saya tambahkan).
implementasi (adaptasi saya ke kode Java Hugo Visser):
(lihat di bawah ini, Anda juga perlu menambahkan file XML)
Fitur bonus dari versi Kotlin
Terkadang Anda tidak ingin semua item RecyclerView dapat diklik.
Untuk menangani ini, saya telah memperkenalkan
ItemClickSupportViewHolder
antarmuka yang dapat Anda gunakanViewHolder
untuk mengontrol item mana yang dapat diklik.Contoh:
Jawa
Pemakaian:
(itu juga mendukung klik item panjang)
Implementasi (komentar ditambahkan oleh saya):
Cara kerjanya (mengapa ini efisien)
Kelas ini berfungsi dengan melampirkan a
RecyclerView.OnChildAttachStateChangeListener
keRecyclerView
. Pendengar ini diberitahu setiap kali seorang anak dilampirkan atau dilepaskan dariRecyclerView
. Kode menggunakan ini untuk menambahkan pendengar tap / klik panjang ke tampilan. Pendengar yang memintaRecyclerView
untukRecyclerView.ViewHolder
yang berisi posisi.Ini lebih efisien daripada solusi lain karena itu menghindari membuat beberapa pendengar untuk setiap tampilan dan terus menghancurkan dan menciptakan mereka saat
RecyclerView
sedang digulir.Anda juga dapat mengadaptasi kode untuk memberikan kembali dudukan itu sendiri jika Anda membutuhkan lebih banyak.
Komentar terakhir
Perlu diingat bahwa benar-benar baik-baik saja untuk menanganinya di adaptor Anda dengan menetapkan pada setiap tampilan daftar Anda pendengar klik, seperti jawaban lain yang diajukan.
Ini bukan hal yang paling efisien untuk dilakukan (Anda membuat pendengar baru setiap kali Anda menggunakan kembali tampilan) tetapi itu berhasil dan dalam kebanyakan kasus itu bukan masalah.
Ini juga agak menentang pemisahan kekhawatiran karena itu sebenarnya bukan Pekerjaan Adaptor untuk mendelegasikan kejadian klik.
sumber
addTo()
danremoveFrom()
. Mesin virtual dikaitkan dengan tag recyclerview dan mati bersamanya atau ketika dihapus secara manual.onCreateViewHolder
dan itu saja.RecyclerView
.Saya suka cara ini dan saya menggunakannya
Dalam
Taruh
Dan buat kelas ini di mana saja Anda inginkan
Saya pernah membaca bahwa ada cara yang lebih baik tetapi saya suka cara ini mudah dan tidak rumit.
sumber
MyOnClickListener
variabel instan, karena Anda akan membuat instance baru setiap kali dengannew
Kata KuncirecyclerView
di MyOnClickListener?Android Recyclerview Dengan
onItemClickListener
, Mengapa kita tidak bisa mencoba ini bekerja sepertiListView
hanya.Sumber: Tautan
Dan Setel ini ke RecyclerView:
sumber
SwipeRefreshLayout
Berkat @marmor, saya memperbarui jawaban saya.
Saya pikir ini adalah solusi yang baik untuk menangani onClick () di konstruktor kelas ViewHolder dan meneruskannya ke kelas induk melalui antarmuka OnItemClickListener .
MyAdapter.java
Penggunaan adaptor di kelas lain:
MyFragment.java
sumber
onBindViewHolder()
juga berkali-kali untuk tampilan yang sama saat menggulir. Bahkan membuat satu punOnClickListener
tidak akan membantu karena Anda akan mengatur ulangOnClickListener
setiap kalionBindViewHolder()
dipanggil. Lihat sebaliknya @ MLProgrammer-CiM solution.MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....
Anda dapat membuat pendengar tunggal untuk semua tampilan.Cowok menggunakan kode ini dalam aktivitas utama Anda. Metode yang Sangat Efisien
Ini kelas adaptor Anda.
Setelah ini, Anda akan mendapatkan metode penggantian ini dalam aktivitas Anda.
sumber
> Apa perbedaan RecyclerView dari Listview?
Satu perbedaan adalah bahwa ada
LayoutManager
kelas dengan RecyclerView dimana Anda dapat mengaturRecyclerView
like- AndaSeperti untuk pengguliran horizontal untuk RecyclerView-
sumber
Menindaklanjuti solusi RxJava MLProgrammer-CiM yang sangat baik
Konsumsi / Amati klik
RxJava 2. +
Ubah tl asli ; dr sebagai:
PublishSubject#asObservable()
telah dihapus. KembalikanPublishSubject
yang merupakanObservable
.sumber
Bagaimana menyatukan semuanya contoh ...
Jenis ViewHolder
sumber
Sejauh yang saya mengerti jawaban MLProgrammer-CiM , cukup mungkin untuk melakukan ini:
sumber
Setelah membaca jawaban @ MLProgrammer-CiM , berikut adalah kode saya:
sumber
getAdapterPosition
dapat kembali-1
untuk "tidak ada posisi".Saya telah melakukan ini, sangat sederhana:
Cukup tambahkan 1 Baris untuk posisi RecyclerView yang Diklik :
Kode lengkap untuk kelas ViewHolder :
Semoga ini bisa membantu Anda.
sumber
getAdapterPosition
bukangetLayoutPosition
. Lindungi dari-1
.Saya menggunakan metode ini untuk memulai Intent dari RecyclerView:
sumber
onBindViewHolder(...)
tidak dipanggil setelahnotify()
metode. Jadi, Anda bisa mendapatkan posisi klik yang salah dalam beberapa situasi.RecyclerView tidak memiliki
onItemClickListener
karena RecyclerView bertanggung jawab atas daur ulang tampilan (kejutan!), Jadi itu adalah tanggung jawab tampilan yang didaur ulang untuk menangani peristiwa klik yang diterimanya.Ini sebenarnya membuatnya lebih mudah digunakan, terutama jika Anda memiliki item yang dapat diklik di banyak tempat.
Bagaimanapun, mendeteksi klik pada item RecyclerView sangat mudah. Yang perlu Anda lakukan adalah mendefinisikan antarmuka (jika Anda tidak menggunakan Kotlin, dalam hal ini Anda baru saja memasukkan lambda):
Kode yang sama di Kotlin:
Hal yang Anda TIDAK perlu melakukan:
1.) Anda tidak perlu mencegat acara sentuh secara manual
2.) Anda tidak perlu dipusingkan dengan pendengar perubahan status anak pasang
3.) Anda tidak perlu PublishSubject / PublishRelay dari RxJava
Cukup gunakan pendengar klik.
sumber
Lihat pendekatan saya tentang ini:
Pertama mendeklarasikan antarmuka seperti ini:
Kemudian buat adaptor:
Dan sekarang mari kita lihat bagaimana mengintegrasikan ini dari sebuah fragmen:
sumber
Jika Anda ingin menambahkan onClick () ke tampilan anak item, misalnya, tombol dalam item, saya menemukan bahwa Anda dapat melakukannya dengan mudah di onCreateViewHolder () dari RecyclerView Anda sendiri. Adject seperti ini:
saya tidak tahu apakah ini cara yang baik, tetapi itu bekerja dengan baik. Jika ada yang punya ide yang lebih baik, sangat senang untuk memberitahu saya dan memperbaiki jawaban saya! :)
sumber
Berikut ini adalah cara untuk mengimplementasikannya dengan mudah jika Anda memiliki daftar POJO dan ingin mengambilnya di klik dari luar adaptor.
Di adaptor Anda, buat pendengar untuk acara klik dan metode untuk mengaturnya:
}
Di ViewHolder Anda, terapkan onClickListener dan buat anggota kelas untuk sementara menyimpan POJO yang disajikan, dengan cara itu (ini adalah contoh, membuat setter akan lebih baik):
Kembali ke adaptor Anda, atur POJO saat ini ketika ViewHolder terikat (atau menjadi nol jika tampilan saat ini tidak memilikinya):
Itu dia, sekarang Anda bisa menggunakannya seperti ini dari fragmen / aktivitas Anda:
sumber
mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
ya kamu bisa
sumber
Di sini Anda dapat menangani beberapa onclick lihat kode di bawah ini dan ini sangat efisien
sumber
itemView
.Ubah komentar saya ...
sumber
getAdapterPosition()
.Periksa ini di mana saya telah menerapkan semua hal dengan cara yang tepat
Kelas RecyclerViewHolder
Adaptor
Antarmuka
sumber
Ini bekerja untuk saya:
sumber
setOnClickListener(holder)
dionBindViewHolder()
. Karena onBindViewHolder (...) tidak dipanggil setelah metode notify (). Jadi, Anda bisa mendapatkan posisi klik yang salah dalam beberapa situasi.onCreateViewHolder
.Akses
mainView
darirowLayout(cell)
untuk AndaRecyclerView
dan AndaOnBindViewHolder
menulis kode ini:sumber
Alih-alih mengimplementasikan antarmuka View.OnClickListener di dalam pemegang tampilan atau membuat dan antarmuka dan mengimplementasikan antarmuka dalam aktivitas Anda .. Saya menggunakan kode ini untuk sederhana pada implementasi OnClickListener.
sumber
Di dalam View Holder
Di dalam OnBindViewHolder ()
Dan beri tahu saya, apakah Anda memiliki pertanyaan tentang solusi ini?
sumber
onCreateViewHolder
untuk kinerja yang lebih baik, tetapi kemudian Anda perlu mendapatkan posisi menggunakangetAdapterPosition()
(dan berjaga-jaga terhadap-1
)sumber
gunakan PlaceHolderView
sumber
Saya menulis perpustakaan untuk menangani tampilan klik item pendaur ulang android. Anda dapat menemukan seluruh tutorial di https://github.com/ChathuraHettiarachchi/RecycleClick
atau untuk menangani item tekan lama dapat Anda gunakan
sumber
animasi recyclerview belum diuji, yang lain normal. Saya pikir itu telah dioptimalkan secara maksimal. Antarmuka memiliki kegunaan lain, untuk sementara waktu bisa Anda abaikan.
Ini adalah Interface
Ini adalah kelas abstrak
Anda hanya membutuhkannya
sumber
Contoh dengan getTag () / setTag () dan pendengar sekali klik untuk seluruh adaptor:
TAG_POSITION didefinisikan dalam file tags.xml sebagai
sumber