This post will show how to filter through a list of data that’s set in a RecyclerView
.
A lot of apps have a search feature where you have a list in a RecyclerView
and a Search menu bar where as the user types, the list filters automatically. I wrote a whole post on how to build a custom search view in one of my posts. Thankfully, this guide will be more brief and straightforward.
The main library that we’ll be utilizing is the same SearchView
library that we used in my Custom SearchView post, MaterialSearchView
.
https://github.com/MiguelCatalan/MaterialSearchView
Except this time, we’ll be using this directly in the screen where you have your RecyclerView
with the list of data.
First, follow the directions of that MaterialSearchView library to set up your menu bars.
Second, in your activity or fragment, set the on query text listener on your search view like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mSearchView = (MaterialSearchView) findViewById(R.id.search_view); mSearchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { mAdapter.setData(mData); mAdapter.notifyDataSetChanged(); mAdapter.getFilter().filter(newText); return true; } }); |
1 2 3 4 5 6 7 8 9 10 11 12 |
mSearchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() { @Override public void onSearchViewShown() { } @Override public void onSearchViewClosed() { mAdapter.setData(mData); mAdapter.notifyDataSetChanged(); } }); |
If you’re observant, you’ll see that we call two methods sequentially, getFilter
and filter on my RecyclerView.Adapter
(variable named mAdapter
). We have a method on my adapter called setData and we use that to set our data. I’ll go over the getFilter
and filter
methods first.
getFilter && filter
First thing we want to do is to implement Filterable
on our RecyclerView.Adapter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> implements Filterable { private Activity mActivity; private ArrayList<Data> mData; @Override public Filter getFilter() { return new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { ArrayList<Data> filteredResults; if (constraint == null || constraint.length() == 0) { filteredResults = mData; } else { filteredResults = getFilteredResults(constraint.toString().toLowerCase()); } FilterResults results = new FilterResults(); results.values = filteredResults; return results; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { mData = (ArrayList<Data>) results.values; DataAdapter.this.notifyDataSetChanged(); } }; } protected ArrayList<Data> getFilteredResults(String constraint) { ArrayList<Data> results = new ArrayList<>(); for (Data data : mData) { if (data.getName().toLowerCase().contains(constraint)) { results.add(data); } } return results; } public DispensaryAdapter(Activity activity, ArrayList<Data> data) { this.mActivity = activity; this.mData = data; } public void setData(ArrayList<Data> data) { this.mData = data; } // More typical RecyclerView stuff below, like ViewHolder pattern and stuff } |
There are a few things going on here. First, we implement Filterable
to our adapter and implement the necessary methods getFilter
and getFilteredResults
. What these two basically do is take in a string (which is passed in from our activity which is bound to the user inputs in our SearchView), and filters through the data list. It scopes down the data based on the filtering conditions we give it, and returns the result. This implements the actual filtering feature that works with the filter method we have in our mAdapter.getFilter().filter(newText)
method chain.
One important thing that we do in our activity though is when the user input is empty. If you look at the listeners that I set on our SearchView
, you’ll see that I constantly set the dataset in our RecyclerView
back with the full data set. The reason for this is because the data set in our adapter will be reduced as the user searches through. Thus, we want to “reset” our list of data back up to full when the user either deletes some of his/her input to search for something else or clears the input in the SearchView
entirely.
Pretty straightforward right?