Creating a filter for the RecyclerView in Android

- Andrés Cruz

En español
Creating a filter for the RecyclerView in Android

Download

In this entry we will see how to create a filter for our RecycleView; In a previous entry we saw how to create lists through lists and grids with the RecycleView Today we will see the same process but with an extra which consists of creating a filter for the previous list through (logically) a search field with a simple EditText.

In our adapter we will create an extra class that we will call CustomFilter that will look like this:

public class CustomFilter extends Filter {
        private ListAdapter listAdapter;

        private CustomFilter(ListAdapter listAdapter) {
            super();
            this.listAdapter = listAdapter;
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            personsFilter.clear();
            final FilterResults results = new FilterResults();
            if (constraint.length() == 0) {
                personsFilter.addAll(persons);
            } else {
                final String filterPattern = constraint.toString().toLowerCase().trim();
                for (final Person person : persons) {
                    if (person.getName().toLowerCase().contains(filterPattern)) {
                        personsFilter.add(person);
                    }
                }
            }
            results.values = personsFilter;
            results.count = personsFilter.size();
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            this.listAdapter.notifyDataSetChanged();
        }
    }

As well as adding an implements to implement the Filterable class in our Adapter:

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> implements Filterable {
    private ArrayList&lt;Person&gt; persons;
    private ArrayList&lt;Person&gt; personsFilter;
    private CustomFilter mFilter;
...
}
public ListAdapter(ArrayList&lt;Person&gt; persons) {

    this.persons = persons;
    this.personsFilter = new ArrayList&lt;&gt;();
    this.personsFilter.addAll(persons);
    this.mFilter = new CustomFilter(ListAdapter.this);
}

In our adapter and the associated getFilter method we override:

@Override
public Filter getFilter() {
    return mFilter;
}

A small piece of information that we have to do in our adapter is to create another list which contains the data filtered by the user and another list that contains the total data that makes up our list without applying any filter; Taking this into account, our constructor and other control methods will be defined as follows:

// Constructor
public ListAdapter(ArrayList&lt;Person&gt; persons) {

	this.persons = persons;
	this.personsFilter = new ArrayList&lt;&gt;();
	this.personsFilter.addAll(persons);
	this.mFilter = new CustomFilter(ListAdapter.this);
}
...
@Override
public int getItemCount() {
	return personsFilter.size();
}
...
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
	viewHolder.nameTextView.setText(personsFilter.get(position).getName());
	viewHolder.descriptionTextView.setText(personsFilter.get(position).getDescription());
	viewHolder.colorLl.setBackgroundColor(Color.parseColor(personsFilter.get(position).getColor()));
}

As you can see we use the filterable ArrayList instead of the complete ArrayList.

We have the adapter ready, now we need to configure the search field in our activity or fragment to be able to filter our list and the associated events; for this we will use an EditText as we mentioned before:

etSearchBox = (EditText) findViewById(R.id.etSearchBox);

And the listener event (listener) that is activated when entering/removing text on it:

        etSearchBox.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                listAdapter.getFilter().filter(s.toString());
            }
            @Override
            public void afterTextChanged(Editable s) {
            }
        });

As you can see, when changing the text, the filter method is called, passing the text to be filtered as a parameter.

Additional data

You can specify the behavior of the filter in the adapter's CustomFilter class by defining the behavior at which time the personsFilter is populated when performing the comparison:

if (person.getName().toLowerCase().contains(filterPattern))

In our case we are interested that it is NOT case sensitive and that it contains (contains) the key word or section and thus have a fairly flexible filter, but you can express it as you wish.

Download

Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.