Cara memfilter RecyclerView dengan SearchView

319

Saya mencoba menerapkan SearchViewdari perpustakaan dukungan. Saya ingin pengguna menggunakan SearchViewfilter Listdari film dalam RecyclerView.

Saya telah mengikuti beberapa tutorial sejauh ini dan saya telah menambahkannya SearchViewke ActionBar, tetapi saya tidak begitu yakin ke mana harus pergi dari sini. Saya telah melihat beberapa contoh tetapi tidak ada yang menunjukkan hasil saat Anda mulai mengetik.

Ini milik saya MainActivity:

public class MainActivity extends ActionBarActivity {

    RecyclerView mRecyclerView;
    RecyclerView.LayoutManager mLayoutManager;
    RecyclerView.Adapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view);

        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        mAdapter = new CardAdapter() {
            @Override
            public Filter getFilter() {
                return null;
            }
        };
        mRecyclerView.setAdapter(mAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Dan ini milik saya Adapter:

public abstract class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> implements Filterable {

    List<Movie> mItems;

    public CardAdapter() {
        super();
        mItems = new ArrayList<Movie>();
        Movie movie = new Movie();
        movie.setName("Spiderman");
        movie.setRating("92");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Doom 3");
        movie.setRating("91");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers");
        movie.setRating("88");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 2");
        movie.setRating("87");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Transformers 3");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Noah");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 2");
        movie.setRating("86");
        mItems.add(movie);

        movie = new Movie();
        movie.setName("Ironman 3");
        movie.setRating("86");
        mItems.add(movie);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_card_item, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Movie movie = mItems.get(i);
        viewHolder.tvMovie.setText(movie.getName());
        viewHolder.tvMovieRating.setText(movie.getRating());
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    class ViewHolder extends RecyclerView.ViewHolder{

        public TextView tvMovie;
        public TextView tvMovieRating;

        public ViewHolder(View itemView) {
            super(itemView);
            tvMovie = (TextView)itemView.findViewById(R.id.movieName);
            tvMovieRating = (TextView)itemView.findViewById(R.id.movieRating);
        }
    }
}
Jacques Krause
sumber

Jawaban:

913

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:

gambar demo

Jika pertama kali ingin bermain-main dengan aplikasi demo, Anda dapat menginstalnya dari Play Store:

Dapatkan di Google Play

Pokoknya mari kita mulai.


Menyiapkan SearchView

Di dalam folder res/menu buat file baru bernama main_menu.xml. Di dalamnya tambahkan item dan atur actionViewClasske android.support.v7.widget.SearchView. Karena Anda menggunakan pustaka dukungan, Anda harus menggunakan namespace pustaka dukungan untuk mengatur actionViewClassatribut. 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 Fragmentatau ActivityAnda harus mengembang menu ini xml seperti biasanya, maka Anda dapat mencariMenuItem yang berisi SearchViewdan menerapkan OnQueryTextListeneryang 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 SearchViewsudah 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 ViewHolderuntuk ExampleModelkelas:

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: SortedListKelas.


DiurutkanDaftar

Ini SortedListadalah alat yang sangat luar biasa yang merupakan bagian dari RecyclerViewperpustakaan. Ini mengurus pemberitahuan Adaptertentang 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 SortedListseperti a Comparator. Tapi bukannya menyortir Listitu digunakan untuk menyortir item di RecyclerView!

The SortedListberinteraksi dengan Adaptermelalui Callbackkelas 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, areContentsTheSamedanareItemsTheSame 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 Comparatoryang 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 SortedListpenggunaan ini untuk menentukan apakah peristiwa perubahan perlu dipanggil - dengan kata lain jika RecyclerViewharus 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 ExampleModelkelas 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 SortedListmenggunakan metode ini untuk memeriksa apakah dua item merujuk pada hal yang sama. Dalam istilah yang paling sederhana (tanpa menjelaskan cara SortedListkerjanya) 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.Callbackpenerapan yang benar kita dapat membuat instance dari SortedList:

final SortedList<ExampleModel> list = new SortedList<>(ExampleModel.class, mCallback);

Sebagai parameter pertama dalam konstruktor, SortedListAnda harus lulus kelas model Anda. Parameter lainnya hanyalah yang SortedList.Callbackkita definisikan di atas.

Sekarang mari kita mulai ke bisnis: Jika kita menerapkan Adapterdengan SortedListitu 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 Comparatordigunakan untuk mengurutkan item dilewatkan melalui konstruktor sehingga kita dapat menggunakan yang sama Adapterbahkan 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 Adapteryang 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 SortedListsudah melakukan ini melalui SortedList.Callback! Selain itu penerapan metode ini cukup mudah dengan satu pengecualian: metode hapus yang menghilangkan Listmodel. Karena SortedListhanya memiliki satu metode hapus yang dapat menghapus satu objek, kita perlu mengulang daftar dan menghapus model satu per satu. Memanggil beginBatchedUpdates()dari awal akan SortedListmengumpulkan 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 SortedListdan sudah ada di SortedListdalamnya tidak akan ditambahkan lagi. Alih-alih SortedListmenggunakan areContentsTheSame()metode untuk mencari tahu apakah objek telah berubah - dan jika memiliki item dalam RecyclerViewakan diperbarui.

Bagaimanapun, apa yang biasanya saya sukai adalah salah satu metode yang memungkinkan saya mengganti semua item RecyclerViewsekaligus. Hapus semua yang tidak ada dalam Listdan 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 Listke SortedListmenggunakan addAll()untuk menambahkan semua item yang belum ada di SortedListdan - sama seperti yang saya jelaskan di atas - perbarui semua item yang sudah ada di SortedListtetapi telah berubah.

Dan dengan itu Adapterselesai. 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 Listsemua model yang mungkin. Untuk contoh ini saya membuat Listdari ExampleModelcontoh 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 Adapterdan set ke RecyclerView. Setelah itu kami membuat Listmodel dari nama-nama film dalam MOVIESarray. 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 Listdari ExampleModels serta string kueri. Kami kemudian memanggil replaceAll()pada Adapterdan lulus dalam disaring Listkembali oleh filter(). Kami juga harus memanggil scrollToPosition(0)pada RecyclerViewuntuk memastikan bahwa pengguna dapat selalu melihat semua item saat mencari sesuatu. Kalau tidak, RecyclerViewmungkin 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 Listkita 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 Adapterberbasis pada yang SortedListlebih 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 Adapterkelas dasar yang sudah menangani berurusan dengan SortedListserta model mengikat untuk ViewHoldercontoh dan menyediakan cara yang nyaman untuk mengimplementasikan Adapterberbasis pada a SortedList. Untuk itu kita harus melakukan dua hal:

  • Kita perlu membuat ViewModelantarmuka yang harus diimplementasikan oleh semua kelas model
  • Kita perlu membuat ViewHoldersubclass yang mendefinisikan bind()metode yang Adapterdapat digunakan untuk mengikat model secara otomatis.

Hal ini memungkinkan kami untuk hanya fokus pada konten yang seharusnya ditampilkan di RecyclerViewhanya dengan mengimplementasikan model dan ada ViewHolderimplementasi yang sesuai . Menggunakan kelas dasar ini kita tidak perlu khawatir tentang detail rumit dari Adapterdan 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 ViewHoldersehingga 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 ViewModelantarmuka:

    public class ExampleModel implements SortedListAdapter.ViewModel {
        ...
    }

Setelah itu kita hanya perlu memperbarui ExampleAdapteruntuk memperpanjang SortedListAdapterdan 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 SortedListAdapterada yang sama add(), remove()atau replaceAll()metode yang asli kami ExampleAdaptermiliki. Ini menggunakan Editorobjek 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 Editorcontoh 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 Editorobjek:

mAdapter.edit()
        .replaceAll(mModels)
        .commit();

Jika Anda lupa menelepon, commit()maka perubahan Anda tidak akan diterapkan!

Xaver Kapeller
sumber
4
@TiagoOliveira Yah itu dibuat untuk hanya bekerja di luar kotak: D Pengikatan data adalah rintangan bagi orang-orang yang tidak terbiasa dengan itu, tapi saya tetap memasukkannya karena itu luar biasa dan saya ingin mempromosikannya. Entah kenapa tidak banyak orang yang tahu tentang itu ...
Xaver Kapeller
78
Saya belum membaca seluruh jawaban, saya harus berhenti membaca di suatu tempat setengah untuk menulis komentar ini - ini adalah salah satu jawaban terbaik yang saya temukan di sini di SO! Terima kasih!
daneejela
16
Saya hanya suka bagaimana Anda seperti: "Tidak jelas dari pertanyaan Anda apa yang sedang Anda hadapi, jadi inilah contoh lengkap yang baru saja saya lakukan": D
Fred
7
+1 hanya untuk menunjukkan kepada kami bahwa Pengikatan Data ada di Android! Saya belum pernah mendengarnya dan sepertinya saya akan mulai menggunakannya. Terima kasih
Jorge Casariego
6
Solusi ini sangat panjang dan umumnya terlalu direkayasa. Pilih yang kedua.
Enrico Casini
194

Yang perlu Anda lakukan adalah menambahkan filtermetode di RecyclerView.Adapter:

public void filter(String text) {
    items.clear();
    if(text.isEmpty()){
        items.addAll(itemsCopy);
    } else{
        text = text.toLowerCase();
        for(PhoneBookItem item: itemsCopy){
            if(item.name.toLowerCase().contains(text) || item.phone.toLowerCase().contains(text)){
                items.add(item);
            }
        }
    }
    notifyDataSetChanged();
}

itemsCopydiinisialisasi dalam konstruktor adaptor seperti itemsCopy.addAll(items).

Jika Anda melakukannya, cukup telepon filterdari OnQueryTextListener:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        adapter.filter(query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        adapter.filter(newText);
        return true;
    }
});

Ini adalah contoh dari memfilter buku telepon saya dengan nama dan nomor telepon.

klimat
sumber
11
Saya pikir ini harus menjadi jawaban yang diterima. Ini lebih sederhana dan hanya berfungsi
Jose_GD
6
Sederhana dan efisien!
AlxDroidDev
11
Perhatikan bahwa Anda kehilangan animasi jika Anda mengikuti pendekatan ini alih-alih jawaban @Xaver Kapeller.
Dipukul
23
Tidak mencoba jawaban yang diterima karena terlalu panjang. Jawaban ini berhasil dan mudah diterapkan. Jangan lupa menambahkan "app: actionViewClass =" android.support.v7.widget.SearchView "pada item menu Anda XML.
SajithK
3
Apa sebenarnya barang dan barang Salin di sini?
Lucky_girl
82

Mengikuti @Shruthi Kamoji dengan cara yang lebih bersih, kita bisa menggunakan filterable, artinya untuk itu:

public abstract class GenericRecycleAdapter<E> extends RecyclerView.Adapter implements Filterable
{
    protected List<E> list;
    protected List<E> originalList;
    protected Context context;

    public GenericRecycleAdapter(Context context,
    List<E> list)
    {
        this.originalList = list;
        this.list = list;
        this.context = context;
    }

    ...

    @Override
    public Filter getFilter() {
        return new Filter() {
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                list = (List<E>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                List<E> filteredResults = null;
                if (constraint.length() == 0) {
                    filteredResults = originalList;
                } else {
                    filteredResults = getFilteredResults(constraint.toString().toLowerCase());
                }

                FilterResults results = new FilterResults();
                results.values = filteredResults;

                return results;
            }
        };
    }

    protected List<E> getFilteredResults(String constraint) {
        List<E> results = new ArrayList<>();

        for (E item : originalList) {
            if (item.getName().toLowerCase().contains(constraint)) {
                results.add(item);
            }
        }
        return results;
    }
} 

E di sini adalah Tipe Generik, Anda dapat memperluasnya menggunakan kelas Anda:

public class customerAdapter extends GenericRecycleAdapter<CustomerModel>

Atau cukup ubah E ke jenis yang Anda inginkan ( <CustomerModel>misalnya)

Kemudian dari searchView (widget Anda dapat memakai menu.xml):

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String text) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String text) {
        yourAdapter.getFilter().filter(text);
        return true;
    }
});
sagit
sumber
Saya menggunakan sesuatu seperti ini! Bekerja dengan baik dan contoh generik!
Mateus
Halo, siapa yang dapat membantu saya selangkah demi selangkah dengan yang ini: stackoverflow.com/questions/40754174/…
Thorvald Olavsen
Jawaban terbersih!
adalpari
4
Ini jauh lebih baik daripada jawaban yang dipilih karena operasi dilakukan pada thread pekerja dalam metode performFiltering.
Hmmm
1
Tetapi Anda menetapkan referensi ke Daftar yang sama untuk variabel yang berbeda. Misalnya this.originalList = daftar; Anda harus menggunakan addAll sebagai gantinya atau meneruskan daftar di konstruktor ArrayList
Florian Walther
5

cukup buat dua daftar di adaptor satu orignal dan satu temp dan mengimplementasikan Filterable .

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                final FilterResults oReturn = new FilterResults();
                final ArrayList<T> results = new ArrayList<>();
                if (origList == null)
                    origList = new ArrayList<>(itemList);
                if (constraint != null && constraint.length() > 0) {
                    if (origList != null && origList.size() > 0) {
                        for (final T cd : origList) {
                            if (cd.getAttributeToSearch().toLowerCase()
                                    .contains(constraint.toString().toLowerCase()))
                                results.add(cd);
                        }
                    }
                    oReturn.values = results;
                    oReturn.count = results.size();//newly Aded by ZA
                } else {
                    oReturn.values = origList;
                    oReturn.count = origList.size();//newly added by ZA
                }
                return oReturn;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(final CharSequence constraint,
                                          FilterResults results) {
                itemList = new ArrayList<>((ArrayList<T>) results.values);
                // FIXME: 8/16/2017 implement Comparable with sort below
                ///Collections.sort(itemList);
                notifyDataSetChanged();
            }
        };
    }

dimana

public GenericBaseAdapter(Context mContext, List<T> itemList) {
        this.mContext = mContext;
        this.itemList = itemList;
        this.origList = itemList;
    }
Zar E Ahmer
sumber
Solusi bagus Saya membuat dua daftar dan menggunakan metode filter sederhana. Sepertinya saya tidak bisa melewatkan posisi adaptor yang benar untuk sebuah item ke Aktivitas berikutnya. Saya akan menghargai setiap pemikiran atau ide yang dapat Anda sarankan untuk ini: stackoverflow.com/questions/46027110/…
AJW
4

Dalam Adaptor:

public void setFilter(List<Channel> newList){
        mChannels = new ArrayList<>();
        mChannels.addAll(newList);
        notifyDataSetChanged();
    }

Dalam Aktivitas:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                newText = newText.toLowerCase();
                ArrayList<Channel> newList = new ArrayList<>();
                for (Channel channel: channels){
                    String channelName = channel.getmChannelName().toLowerCase();
                    if (channelName.contains(newText)){
                        newList.add(channel);
                    }
                }
                mAdapter.setFilter(newList);
                return true;
            }
        });
Firoz Ahmed
sumber
3

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:

@Dao
public interface CustomDAO{

@Query("SELECT * FROM words_table WHERE column LIKE :searchquery")
    public LiveData<List<Word>> searchFor(String searchquery);
}

2. Buat objek ViewModel untuk memperbarui data Anda secara langsung melalui metode yang akan menghubungkan DAO dan UI Anda

public class CustomViewModel extends AndroidViewModel {

    private final AppDatabase mAppDatabase;

    public WordListViewModel(@NonNull Application application) {
        super(application);
        this.mAppDatabase = AppDatabase.getInstance(application.getApplicationContext());
    }

    public LiveData<List<Word>> searchQuery(String query) {
        return mAppDatabase.mWordDAO().searchFor(query);
    }

}

3. Panggil data Anda dari ViewModel on the fly dengan mengirimkan kueri melalui onQueryTextListener seperti di bawah ini:

Di dalam onCreateOptionsMenumengatur pendengar Anda sebagai berikut

searchView.setOnQueryTextListener(onQueryTextListener);

Siapkan pendengar kueri Anda di suatu tempat di kelas SearchActivity Anda sebagai berikut

private android.support.v7.widget.SearchView.OnQueryTextListener onQueryTextListener =
            new android.support.v7.widget.SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    getResults(query);
                    return true;
                }

                @Override
                public boolean onQueryTextChange(String newText) {
                    getResults(newText);
                    return true;
                }

                private void getResults(String newText) {
                    String queryText = "%" + newText + "%";
                    mCustomViewModel.searchQuery(queryText).observe(
                            SearchResultsActivity.this, new Observer<List<Word>>() {
                                @Override
                                public void onChanged(@Nullable List<Word> words) {
                                    if (words == null) return;
                                    searchAdapter.submitList(words);
                                }
                            });
                }
            };

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 :).

Panos Gr
sumber
1

Ini adalah jawaban saya untuk memperluas @ klimat agar tidak kehilangan animasi penyaringan.

public void filter(String query){
    int completeListIndex = 0;
    int filteredListIndex = 0;
    while (completeListIndex < completeList.size()){
        Movie item = completeList.get(completeListIndex);
        if(item.getName().toLowerCase().contains(query)){
            if(filteredListIndex < filteredList.size()) {
                Movie filter = filteredList.get(filteredListIndex);
                if (!item.getName().equals(filter.getName())) {
                    filteredList.add(filteredListIndex, item);
                    notifyItemInserted(filteredListIndex);
                }
            }else{
                filteredList.add(filteredListIndex, item);
                notifyItemInserted(filteredListIndex);
            }
            filteredListIndex++;
        }
        else if(filteredListIndex < filteredList.size()){
            Movie filter = filteredList.get(filteredListIndex);
            if (item.getName().equals(filter.getName())) {
                filteredList.remove(filteredListIndex);
                notifyItemRemoved(filteredListIndex);
            }
        }
        completeListIndex++;
    }
}

Pada dasarnya yang dilakukan adalah melihat daftar lengkap dan menambahkan / menghapus item ke daftar yang difilter satu per satu.

AhmadF
sumber
0

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

public void addItem(int position, ExampleModel model) {
    if(position >= mModel.size()) {
        mModel.add(model);
        notifyItemInserted(mModel.size()-1);
    } else {
        mModels.add(position, model);
        notifyItemInserted(position);
    }
}

Dan memodifikasi juga dalam fungsionalitas moveItem

public void moveItem(int fromPosition, int toPosition) {
    final ExampleModel model = mModels.remove(fromPosition);
    if(toPosition >= mModels.size()) {
        mModels.add(model);
        notifyItemMoved(fromPosition, mModels.size()-1);
    } else {
        mModels.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition); 
    }
}

Semoga itu bisa membantu Anda!

toidv
sumber
Sama sekali tidak perlu.
Xaver Kapeller
Untuk jawaban asli jika Anda tidak melakukan itu, IndexOutOfBoundsException akan terjadi, jadi mengapa tidak perlu ???? Apakah Anda ingin log? @XaverKapeller
toidv
Tidak ada pengecualian hanya akan terjadi jika Anda menerapkan Adaptercara yang salah. Tanpa melihat kode Anda, saya kira masalah yang paling mungkin adalah bahwa Anda tidak meneruskan salinan daftar dengan semua item ke Adapter.
Xaver Kapeller
Log kesalahan: W / System.err: java.lang.IndexOutOfBoundsException: Indeks tidak valid 36, ukurannya adalah 35 W / System.err: di java.util.ArrayList.throwIndexOutOfOoundsBcException (ArrayList.java:255) W / System.err: di java.util.ArrayList.add (ArrayList.java:147) W / System.err: di com.quomodo.inploi.ui.adapter.MultipleSelectFilterAdapter.addItem (MultipleSelectFilterAdapter.java:125) W / System.err: at com .quomodo.inploi.ui.adapter.MultipleSelectFilterAdapter.applyAndAnimateAdditions (MultipleSelectFilterAdapter.java:78)
toidv
Tolong bantu untuk memeriksa kode sumber di bawah ini @XaverKapeller gist.github.com/toidv/fe71dc45169e4138271b52fdb29420c5
toidv
0

Recyclerview dengan searchview dan clicklistener

Tambahkan antarmuka di adaptor Anda.

public interface SelectedUser{

    void selectedUser(UserModel userModel);

}

mengimplementasikan antarmuka dalam aktivitas utama Anda dan menimpa metode. @Override public void selectedUser (UserModel userModel) {

    startActivity(new Intent(MainActivity.this, SelectedUserActivity.class).putExtra("data",userModel));



}

Tutorial dan kode sumber lengkap: Recyclerview dengan searchview dan onclicklistener

Richard Kamere
sumber
-1

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

public class ContactListRecyclerAdapter extends RecyclerView.Adapter<ContactListRecyclerAdapter.ContactViewHolder> implements Filterable {

Context mContext;
ArrayList<Contact> customerList;
ArrayList<Contact> parentCustomerList;


public ContactListRecyclerAdapter(Context context,ArrayList<Contact> customerList)
{
    this.mContext=context;
    this.customerList=customerList;
    if(customerList!=null)
    parentCustomerList=new ArrayList<>(customerList);
}

   // other overrided methods

@Override
public Filter getFilter() {
    return new FilterCustomerSearch(this,parentCustomerList);
}
}

// Kelas filter

import android.widget.Filter;
import java.util.ArrayList;


public class FilterCustomerSearch extends Filter
{
private final ContactListRecyclerAdapter mAdapter;
ArrayList<Contact> contactList;
ArrayList<Contact> filteredList;

public FilterCustomerSearch(ContactListRecyclerAdapter mAdapter,ArrayList<Contact> contactList) {
    this.mAdapter = mAdapter;
    this.contactList=contactList;
    filteredList=new ArrayList<>();
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
    filteredList.clear();
    final FilterResults results = new FilterResults();

    if (constraint.length() == 0) {
        filteredList.addAll(contactList);
    } else {
        final String filterPattern = constraint.toString().toLowerCase().trim();

        for (final Contact contact : contactList) {
            if (contact.customerName.contains(constraint)) {
                filteredList.add(contact);
            }
            else if (contact.emailId.contains(constraint))
            {
                filteredList.add(contact);

            }
            else if(contact.phoneNumber.contains(constraint))
                filteredList.add(contact);
        }
    }
    results.values = filteredList;
    results.count = filteredList.size();
    return results;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    mAdapter.customerList.clear();
    mAdapter.customerList.addAll((ArrayList<Contact>) results.values);
    mAdapter.notifyDataSetChanged();
}

}

// Kelas aktivitas

public class HomeCrossFadeActivity extends AppCompatActivity implements View.OnClickListener,OnFragmentInteractionListener,OnTaskCompletedListner
{
Fragment fragment;
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_homecrossfadeslidingpane2);CardView mCard;
   setContentView(R.layout.your_main_xml);}
   //other overrided methods
  @Override
   public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.

    MenuInflater inflater = getMenuInflater();
    // Inflate menu to add items to action bar if it is present.
    inflater.inflate(R.menu.menu_customer_view_and_search, menu);
    // Associate searchable configuration with the SearchView
    SearchManager searchManager =
            (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView =
            (SearchView) menu.findItem(R.id.menu_search).getActionView();
    searchView.setQueryHint("Search Customer");
    searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if(fragment instanceof CustomerDetailsViewWithModifyAndSearch)
                ((CustomerDetailsViewWithModifyAndSearch)fragment).adapter.getFilter().filter(newText);
            return false;
        }
    });



    return true;
}
}

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.

Shruthi Kamoji
sumber