pengantar
Karena tidak benar-benar jelas dari pertanyaan Anda apa sebenarnya yang Anda hadapi, saya menulis langkah cepat ini tentang bagaimana menerapkan fitur ini; jika Anda masih memiliki pertanyaan, jangan ragu untuk bertanya.
Saya memiliki contoh kerja dari semua yang saya bicarakan di sini di Repositori GitHub ini .
Jika Anda ingin tahu lebih banyak tentang contoh proyek, kunjungi beranda proyek .
Bagaimanapun hasilnya akan terlihat seperti ini:
Jika pertama kali ingin bermain-main dengan aplikasi demo, Anda dapat menginstalnya dari Play Store:
Pokoknya mari kita mulai.
Menyiapkan SearchView
Di dalam folder res/menu
buat file baru bernama main_menu.xml
. Di dalamnya tambahkan item dan atur actionViewClass
ke android.support.v7.widget.SearchView
. Karena Anda menggunakan pustaka dukungan, Anda harus menggunakan namespace pustaka dukungan untuk mengatur actionViewClass
atribut. File xml Anda akan terlihat seperti ini:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
</menu>
Di Anda Fragment
atau Activity
Anda harus mengembang menu ini xml seperti biasanya, maka Anda dapat mencariMenuItem
yang berisi SearchView
dan menerapkan OnQueryTextListener
yang akan kita gunakan untuk mendengarkan perubahan pada teks yang dimasukkan ke SearchView
:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
final MenuItem searchItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
// Here is where we are going to implement the filter logic
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
Dan sekarang SearchView
sudah siap untuk digunakan. Kami akan menerapkan logika filter nanti onQueryTextChange()
setelah kami selesai mengimplementasikan Adapter
.
Menyiapkan Adapter
Pertama dan terutama, ini adalah kelas model yang akan saya gunakan untuk contoh ini:
public class ExampleModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
}
Hanya saja model dasar Anda yang akan menampilkan teks di RecyclerView
. Ini adalah tata letak yang akan saya gunakan untuk menampilkan teks:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="com.github.wrdlbrnft.searchablerecyclerviewdemo.ui.models.ExampleModel"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="@{model.text}"/>
</FrameLayout>
</layout>
Seperti yang Anda lihat saya menggunakan Binding Data. Jika Anda belum pernah bekerja dengan pengikatan data sebelum jangan berkecil hati! Ini sangat sederhana dan kuat, namun saya tidak dapat menjelaskan cara kerjanya dalam lingkup jawaban ini.
Ini ViewHolder
untuk ExampleModel
kelas:
public class ExampleViewHolder extends RecyclerView.ViewHolder {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
public void bind(ExampleModel item) {
mBinding.setModel(item);
}
}
Sekali lagi tidak ada yang istimewa. Itu hanya menggunakan data yang mengikat untuk mengikat kelas model ke tata letak ini seperti yang telah kita tentukan dalam tata letak xml di atas.
Sekarang kita akhirnya dapat sampai pada bagian yang sangat menarik: Menulis Adaptor. Saya akan melewatkan implementasi dasar dariAdapter
dan bukannya akan berkonsentrasi pada bagian-bagian yang relevan untuk jawaban ini.
Tetapi pertama-tama ada satu hal yang harus kita bicarakan: SortedList
Kelas.
DiurutkanDaftar
Ini SortedList
adalah alat yang sangat luar biasa yang merupakan bagian dari RecyclerView
perpustakaan. Ini mengurus pemberitahuan Adapter
tentang perubahan set data dan melakukannya dengan cara yang sangat efisien. Satu-satunya hal yang mengharuskan Anda lakukan adalah menentukan urutan elemen. Anda perlu melakukan itu dengan menerapkan compare()
metode yang membandingkan dua elemen SortedList
seperti a Comparator
. Tapi bukannya menyortir List
itu digunakan untuk menyortir item di RecyclerView
!
The SortedList
berinteraksi dengan Adapter
melalui Callback
kelas yang Anda harus melaksanakan:
private final SortedList.Callback<ExampleModel> mCallback = new SortedList.Callback<ExampleModel>() {
@Override
public void onInserted(int position, int count) {
mAdapter.notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
mAdapter.notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
mAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
mAdapter.notifyItemRangeChanged(position, count);
}
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
}
Dalam metode di atas callback seperti onMoved
, onInserted
, dll Anda harus memanggil setara memberitahukan metode Anda Adapter
. Tiga metode di bagian bawah compare
, areContentsTheSame
danareItemsTheSame
Anda harus menerapkan sesuai dengan objek apa yang ingin Anda tampilkan dan dalam urutan apa objek ini akan muncul di layar.
Mari kita pelajari metode ini satu per satu:
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
Ini adalah compare()
metode yang saya bicarakan sebelumnya. Dalam contoh ini saya hanya meneruskan panggilan ke Comparator
yang membandingkan kedua model. Jika Anda ingin item muncul dalam urutan abjad di layar. Komparator ini mungkin terlihat seperti ini:
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
Sekarang mari kita lihat metode selanjutnya:
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
Tujuan metode ini adalah untuk menentukan apakah konten model telah berubah. The SortedList
penggunaan ini untuk menentukan apakah peristiwa perubahan perlu dipanggil - dengan kata lain jika RecyclerView
harus crossfade versi lama dan baru. Jika model Anda memiliki kelas yang benar equals()
dan hashCode()
implementasi Anda biasanya dapat mengimplementasikannya seperti di atas. Jika kita menambahkan equals()
dan hashCode()
implementasi ke ExampleModel
kelas itu akan terlihat seperti ini:
public class ExampleModel implements SortedListAdapter.ViewModel {
private final long mId;
private final String mText;
public ExampleModel(long id, String text) {
mId = id;
mText = text;
}
public long getId() {
return mId;
}
public String getText() {
return mText;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExampleModel model = (ExampleModel) o;
if (mId != model.mId) return false;
return mText != null ? mText.equals(model.mText) : model.mText == null;
}
@Override
public int hashCode() {
int result = (int) (mId ^ (mId >>> 32));
result = 31 * result + (mText != null ? mText.hashCode() : 0);
return result;
}
}
Catatan samping cepat: Sebagian besar IDE seperti Android Studio, IntelliJ dan Eclipse memiliki fungsi untuk menghasilkan equals()
danhashCode()
implementasi untuk Anda dengan menekan satu tombol! Jadi Anda tidak harus menerapkannya sendiri. Cari di internet cara kerjanya di IDE Anda!
Sekarang mari kita lihat metode terakhir:
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
The SortedList
menggunakan metode ini untuk memeriksa apakah dua item merujuk pada hal yang sama. Dalam istilah yang paling sederhana (tanpa menjelaskan cara SortedList
kerjanya) ini digunakan untuk menentukan apakah suatu objek sudah terkandung dalamList
dan apakah salah satu dari add, move atau perubahan animasi perlu dimainkan. Jika model Anda memiliki id, Anda biasanya hanya membandingkan id dalam metode ini. Jika tidak, Anda perlu mencari cara lain untuk memeriksanya, tetapi bagaimanapun Anda akhirnya menerapkan ini tergantung pada aplikasi spesifik Anda. Biasanya ini adalah opsi paling sederhana untuk memberikan semua model id - yang misalnya bisa menjadi bidang kunci utama jika Anda meminta data dari database.
Dengan SortedList.Callback
penerapan yang benar kita dapat membuat instance dari SortedList
:
final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);
Sebagai parameter pertama dalam konstruktor, SortedList
Anda harus lulus kelas model Anda. Parameter lainnya hanyalah yang SortedList.Callback
kita definisikan di atas.
Sekarang mari kita mulai ke bisnis: Jika kita menerapkan Adapter
dengan SortedList
itu akan terlihat seperti ini:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
});
private final LayoutInflater mInflater;
private final Comparator<ExampleModel> mComparator;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
The Comparator
digunakan untuk mengurutkan item dilewatkan melalui konstruktor sehingga kita dapat menggunakan yang sama Adapter
bahkan jika item yang seharusnya ditampilkan dalam urutan yang berbeda.
Sekarang kita hampir selesai! Tetapi pertama-tama kita perlu cara untuk menambah atau menghapus item ke Adapter
. Untuk tujuan ini, kami dapat menambahkan metode Adapter
yang memungkinkan kami menambah dan menghapus item ke SortedList
:
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
Kami tidak perlu memanggil metode pemberitahuan apa pun di sini karena SortedList
sudah melakukan ini melalui SortedList.Callback
! Selain itu penerapan metode ini cukup mudah dengan satu pengecualian: metode hapus yang menghilangkan List
model. Karena SortedList
hanya memiliki satu metode hapus yang dapat menghapus satu objek, kita perlu mengulang daftar dan menghapus model satu per satu. Memanggil beginBatchedUpdates()
dari awal akan SortedList
mengumpulkan semua perubahan yang akan kita lakukan untuk bersama dan meningkatkan kinerja. Ketika kita sebut endBatchedUpdates()
denganRecyclerView
diberitahukan tentang semua perubahan sekaligus.
Selain itu apa yang harus Anda pahami adalah bahwa jika Anda menambahkan objek ke SortedList
dan sudah ada di SortedList
dalamnya tidak akan ditambahkan lagi. Alih-alih SortedList
menggunakan areContentsTheSame()
metode untuk mencari tahu apakah objek telah berubah - dan jika memiliki item dalam RecyclerView
akan diperbarui.
Bagaimanapun, apa yang biasanya saya sukai adalah salah satu metode yang memungkinkan saya mengganti semua item RecyclerView
sekaligus. Hapus semua yang tidak ada dalam List
dan tambahkan semua item yang hilang dari SortedList
:
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
Metode ini sekali lagi mengelompokkan semua pembaruan bersama untuk meningkatkan kinerja. Loop pertama terbalik karena menghapus item di awal akan mengacaukan indeks semua item yang muncul setelahnya dan ini dapat menyebabkan beberapa kasus masalah seperti inkonsistensi data. Setelah itu kita tambahkan saja List
ke SortedList
menggunakan addAll()
untuk menambahkan semua item yang belum ada di SortedList
dan - sama seperti yang saya jelaskan di atas - perbarui semua item yang sudah ada di SortedList
tetapi telah berubah.
Dan dengan itu Adapter
selesai. Semuanya akan terlihat seperti ini:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleViewHolder> {
private final SortedList<ExampleModel> mSortedList = new SortedList<>(ExampleModel.class, new SortedList.Callback<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return mComparator.compare(a, b);
}
@Override
public void onInserted(int position, int count) {
notifyItemRangeInserted(position, count);
}
@Override
public void onRemoved(int position, int count) {
notifyItemRangeRemoved(position, count);
}
@Override
public void onMoved(int fromPosition, int toPosition) {
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onChanged(int position, int count) {
notifyItemRangeChanged(position, count);
}
@Override
public boolean areContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
@Override
public boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1 == item2;
}
});
private final Comparator<ExampleModel> mComparator;
private final LayoutInflater mInflater;
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
mInflater = LayoutInflater.from(context);
mComparator = comparator;
}
@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(mInflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
final ExampleModel model = mSortedList.get(position);
holder.bind(model);
}
public void add(ExampleModel model) {
mSortedList.add(model);
}
public void remove(ExampleModel model) {
mSortedList.remove(model);
}
public void add(List<ExampleModel> models) {
mSortedList.addAll(models);
}
public void remove(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (ExampleModel model : models) {
mSortedList.remove(model);
}
mSortedList.endBatchedUpdates();
}
public void replaceAll(List<ExampleModel> models) {
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() - 1; i >= 0; i--) {
final ExampleModel model = mSortedList.get(i);
if (!models.contains(model)) {
mSortedList.remove(model);
}
}
mSortedList.addAll(models);
mSortedList.endBatchedUpdates();
}
@Override
public int getItemCount() {
return mSortedList.size();
}
}
Satu-satunya hal yang hilang sekarang adalah menerapkan pemfilteran!
Menerapkan logika filter
Untuk mengimplementasikan logika filter, pertama-tama kita harus mendefinisikan List
semua model yang mungkin. Untuk contoh ini saya membuat List
dari ExampleModel
contoh dari array film:
private static final String[] MOVIES = new String[]{
...
};
private static final Comparator<ExampleModel> ALPHABETICAL_COMPARATOR = new Comparator<ExampleModel>() {
@Override
public int compare(ExampleModel a, ExampleModel b) {
return a.getText().compareTo(b.getText());
}
};
private ExampleAdapter mAdapter;
private List<ExampleModel> mModels;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mAdapter = new ExampleAdapter(this, ALPHABETICAL_COMPARATOR);
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mBinding.recyclerView.setAdapter(mAdapter);
mModels = new ArrayList<>();
for (String movie : MOVIES) {
mModels.add(new ExampleModel(movie));
}
mAdapter.add(mModels);
}
Tidak ada yang istimewa terjadi di sini, kami hanya instantiate Adapter
dan set ke RecyclerView
. Setelah itu kami membuat List
model dari nama-nama film dalam MOVIES
array. Kemudian kami menambahkan semua model ke SortedList
.
Sekarang kita dapat kembali ke onQueryTextChange()
yang telah kita tentukan sebelumnya dan mulai menerapkan logika filter:
@Override
public boolean onQueryTextChange(String query) {
final List<ExampleModel> filteredModelList = filter(mModels, query);
mAdapter.replaceAll(filteredModelList);
mBinding.recyclerView.scrollToPosition(0);
return true;
}
Ini lagi cukup lurus ke depan. Kami memanggil metode filter()
dan meneruskan List
dari ExampleModel
s serta string kueri. Kami kemudian memanggil replaceAll()
pada Adapter
dan lulus dalam disaring List
kembali oleh filter()
. Kami juga harus memanggil scrollToPosition(0)
pada RecyclerView
untuk memastikan bahwa pengguna dapat selalu melihat semua item saat mencari sesuatu. Kalau tidak, RecyclerView
mungkin tetap dalam posisi digulir ke bawah saat penyaringan dan kemudian menyembunyikan beberapa item. Menggulir ke atas memastikan pengalaman pengguna yang lebih baik saat mencari.
Satu-satunya yang tersisa untuk dilakukan sekarang adalah mengimplementasikannya filter()
sendiri:
private static List<ExampleModel> filter(List<ExampleModel> models, String query) {
final String lowerCaseQuery = query.toLowerCase();
final List<ExampleModel> filteredModelList = new ArrayList<>();
for (ExampleModel model : models) {
final String text = model.getText().toLowerCase();
if (text.contains(lowerCaseQuery)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
Hal pertama yang kami lakukan di sini adalah memanggil toLowerCase()
string kueri. Kami tidak ingin fungsi pencarian kami peka huruf besar kecil dan dengan memanggil toLowerCase()
semua string yang kami bandingkan kami dapat memastikan bahwa kami mengembalikan hasil yang sama terlepas dari huruf besar-kecil. Itu kemudian hanya mengulangi semua model di List
kita melewati ke dalamnya dan memeriksa apakah string kueri terkandung dalam teks model. Jika ya maka model ditambahkan ke filter List
.
Dan itu dia! Kode di atas akan berjalan pada API level 7 dan di atas dan dimulai dengan API level 11 Anda mendapatkan animasi item gratis!
Saya menyadari bahwa ini adalah deskripsi yang sangat terperinci yang mungkin membuat semua ini tampak lebih rumit daripada yang sebenarnya, tetapi ada cara kita dapat menggeneralisasi seluruh masalah ini dan membuat implementasi Adapter
berbasis pada yang SortedList
lebih sederhana.
Menyamaratakan masalah dan menyederhanakan Adaptor
Pada bagian ini saya tidak akan membahas banyak detail - sebagian karena saya berlari melawan batas karakter untuk jawaban pada Stack Overflow tetapi juga karena sebagian besar sudah dijelaskan di atas - tetapi untuk meringkas perubahan: Kita dapat menerapkan Adapter
kelas dasar yang sudah menangani berurusan dengan SortedList
serta model mengikat untuk ViewHolder
contoh dan menyediakan cara yang nyaman untuk mengimplementasikan Adapter
berbasis pada a SortedList
. Untuk itu kita harus melakukan dua hal:
- Kita perlu membuat
ViewModel
antarmuka yang harus diimplementasikan oleh semua kelas model
- Kita perlu membuat
ViewHolder
subclass yang mendefinisikan bind()
metode yang Adapter
dapat digunakan untuk mengikat model secara otomatis.
Hal ini memungkinkan kami untuk hanya fokus pada konten yang seharusnya ditampilkan di RecyclerView
hanya dengan mengimplementasikan model dan ada ViewHolder
implementasi yang sesuai . Menggunakan kelas dasar ini kita tidak perlu khawatir tentang detail rumit dari Adapter
dan SortedList
.
DiurutkanDaftarAdapter
Karena batas karakter untuk jawaban di StackOverflow, saya tidak bisa melalui setiap langkah menerapkan kelas dasar ini atau bahkan menambahkan kode sumber lengkap di sini, tetapi Anda dapat menemukan kode sumber lengkap dari kelas dasar ini - saya menyebutnya SortedListAdapter
- dalam hal ini GitHub Gist .
Untuk mempermudah hidup Anda, saya telah menerbitkan perpustakaan di jCenter yang berisi SortedListAdapter
! Jika Anda ingin menggunakannya maka yang perlu Anda lakukan adalah menambahkan dependensi ini ke file build.gradle aplikasi Anda:
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.1'
Anda dapat menemukan informasi lebih lanjut tentang perpustakaan ini di beranda perpustakaan .
Menggunakan SortedListAdapter
Untuk menggunakan SortedListAdapter
kita harus membuat dua perubahan:
Ubah ViewHolder
sehingga memanjang SortedListAdapter.ViewHolder
. Parameter tipe harus menjadi model yang harus terikat pada ini ViewHolder
- dalam hal ini ExampleModel
. Anda harus mengikat data ke model Anda performBind()
sebagai ganti bind()
.
public class ExampleViewHolder extends SortedListAdapter.ViewHolder<ExampleModel> {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
@Override
protected void performBind(ExampleModel item) {
mBinding.setModel(item);
}
}
Pastikan semua model Anda menerapkan ViewModel
antarmuka:
public class ExampleModel implements SortedListAdapter.ViewModel {
...
}
Setelah itu kita hanya perlu memperbarui ExampleAdapter
untuk memperpanjang SortedListAdapter
dan menghapus semua yang tidak kita butuhkan lagi. Parameter tipe harus tipe model yang Anda kerjakan - dalam hal ini ExampleModel
. Tetapi jika Anda bekerja dengan berbagai jenis model maka atur parameter type ke ViewModel
.
public class ExampleAdapter extends SortedListAdapter<ExampleModel> {
public ExampleAdapter(Context context, Comparator<ExampleModel> comparator) {
super(context, ExampleModel.class, comparator);
}
@Override
protected ViewHolder<? extends ExampleModel> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
final ItemExampleBinding binding = ItemExampleBinding.inflate(inflater, parent, false);
return new ExampleViewHolder(binding);
}
@Override
protected boolean areItemsTheSame(ExampleModel item1, ExampleModel item2) {
return item1.getId() == item2.getId();
}
@Override
protected boolean areItemContentsTheSame(ExampleModel oldItem, ExampleModel newItem) {
return oldItem.equals(newItem);
}
}
Setelah itu kita selesai! Namun satu hal lagi yang disebutkan: Tidak SortedListAdapter
ada yang sama add()
, remove()
atau replaceAll()
metode yang asli kami ExampleAdapter
miliki. Ini menggunakan Editor
objek terpisah untuk memodifikasi item dalam daftar yang dapat diakses melalui edit()
metode ini. Jadi, jika Anda ingin menghapus atau menambahkan item yang harus Anda panggil edit()
kemudian tambahkan dan hapus item pada Editor
contoh ini dan setelah Anda selesai, panggil commit()
itu untuk menerapkan perubahan pada SortedList
:
mAdapter.edit()
.remove(modelToRemove)
.add(listOfModelsToAdd)
.commit();
Semua perubahan yang Anda lakukan dengan cara ini dikumpulkan bersama untuk meningkatkan kinerja. The replaceAll()
Metode kami menerapkan dalam bab-bab di atas juga hadir pada ini Editor
objek:
mAdapter.edit()
.replaceAll(mModels)
.commit();
Jika Anda lupa menelepon, commit()
maka perubahan Anda tidak akan diterapkan!
Yang perlu Anda lakukan adalah menambahkan
filter
metode diRecyclerView.Adapter
:itemsCopy
diinisialisasi dalam konstruktor adaptor sepertiitemsCopy.addAll(items)
.Jika Anda melakukannya, cukup telepon
filter
dariOnQueryTextListener
:Ini adalah contoh dari memfilter buku telepon saya dengan nama dan nomor telepon.
sumber
Mengikuti @Shruthi Kamoji dengan cara yang lebih bersih, kita bisa menggunakan filterable, artinya untuk itu:
E di sini adalah Tipe Generik, Anda dapat memperluasnya menggunakan kelas Anda:
Atau cukup ubah E ke jenis yang Anda inginkan (
<CustomerModel>
misalnya)Kemudian dari searchView (widget Anda dapat memakai menu.xml):
sumber
dimana
sumber
Dalam Adaptor:
Dalam Aktivitas:
sumber
Dengan Komponen Arsitektur Android melalui penggunaan LiveData ini dapat dengan mudah diimplementasikan dengan semua jenis Adaptor . Anda cukup melakukan langkah-langkah berikut:
1. Atur data Anda untuk kembali dari Room Database sebagai LiveData seperti pada contoh di bawah ini:
2. Buat objek ViewModel untuk memperbarui data Anda secara langsung melalui metode yang akan menghubungkan DAO dan UI Anda
3. Panggil data Anda dari ViewModel on the fly dengan mengirimkan kueri melalui onQueryTextListener seperti di bawah ini:
Di dalam
onCreateOptionsMenu
mengatur pendengar Anda sebagai berikutSiapkan pendengar kueri Anda di suatu tempat di kelas SearchActivity Anda sebagai berikut
Catatan : Langkah (1.) dan (2.) adalah standar AAC ViewModel dan implementasi DAO , satu-satunya "keajaiban" yang terjadi di sini adalah di OnQueryTextListener yang akan memperbarui hasil daftar Anda secara dinamis saat teks kueri berubah.
Jika Anda perlu klarifikasi lebih lanjut tentang masalah ini, jangan ragu untuk bertanya. Saya harap ini membantu :).
sumber
Ini adalah jawaban saya untuk memperluas @ klimat agar tidak kehilangan animasi penyaringan.
Pada dasarnya yang dilakukan adalah melihat daftar lengkap dan menambahkan / menghapus item ke daftar yang difilter satu per satu.
sumber
Saya sarankan untuk memodifikasi solusi @Xaver Kapeller dengan 2 hal di bawah ini untuk menghindari masalah setelah Anda menghapus teks yang dicari (filter tidak berfungsi lagi) karena daftar belakang adaptor memiliki ukuran lebih kecil daripada daftar filter dan IndexOutOfBoundsException terjadi. Jadi kodenya perlu dimodifikasi seperti di bawah ini
Dan memodifikasi juga dalam fungsionalitas moveItem
Semoga itu bisa membantu Anda!
sumber
Adapter
cara yang salah. Tanpa melihat kode Anda, saya kira masalah yang paling mungkin adalah bahwa Anda tidak meneruskan salinan daftar dengan semua item keAdapter
.Tambahkan antarmuka di adaptor Anda.
mengimplementasikan antarmuka dalam aktivitas utama Anda dan menimpa metode. @Override public void selectedUser (UserModel userModel) {
Tutorial dan kode sumber lengkap: Recyclerview dengan searchview dan onclicklistener
sumber
Saya telah memecahkan masalah yang sama menggunakan tautan dengan beberapa modifikasi di dalamnya. Filter pencarian di RecyclerView with Cards. Apakah itu mungkin? (semoga ini membantu).
Ini kelas adaptor saya
// Kelas filter
}
// Kelas aktivitas
Dalam metode OnQueryTextChangeListener () gunakan adaptor Anda. Saya telah mengubahnya menjadi fragmen karena adpter saya terpecah-pecah. Anda dapat menggunakan adaptor secara langsung jika ada di kelas aktivitas Anda.
sumber