Creando un filtro para los RecycleView en Android

- Andrés Cruz

In english
Creando un filtro para los RecycleView en Android

Descargar

En esta entrada veremos cómo crear un filtro para nuestros RecycleView; en una entrada anterior vimos cómo crear listados a través de listas y grids con el RecycleView hoy veremos el mismo proceso pero con un extra el cual consiste en crear un filtro para el listado anterior a través (lógicamente) por un campo de búsqueda con un simple EditText.

En nuestro adaptador crearemos una clase extra que llamaremos CustomFilter que lucirá de la siguiente manera:

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();
        }
    }

Además de agregar un implements para implementar la clase Filterable en nuestro 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);
}

En nuestro adaptador y el método asociado getFilter que sobreescribimos:

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

Un pequeño dato que tenemos que hacer en nuestro adaptador es crear otra lista la cual contiene la data filtrada por el usuario y otro listado que contiene el total de la data que conforma nuestro listado sin aplicar ningún filtro; teniendo esto en cuenta nuestra el constructor y así como otros métodos de control quedaran definidos de la siguiente manera:

// 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()));
}

Cómo ves empleamos el ArrayList filtrable en vez del ArrayList completo.

Tenemos listo el adaptador, ahora falta configurar en nuestra actividad o fragment el campo de búsqueda para poder filtrar nuestro listado y los eventos asociados; para ello emplearemos un EditText como comentamos anteriormente:

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

Y el evento escuchador (listener) que se activa al ingresar/remover texto sobre el mismo:

        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) {
            }
        });

Cómo puedes ver, al cambiar el texto se invoca el método filter pasando como parámetro el texto a filtrar.

Dato adicional

Puedes especificar el funcionamiento del filtro en la clase CustomFilter del adaptador definiendo el comportamiento en el momento en el que se realiza el llenado de personsFilter al realizar la comparación:

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

En nuestro caso nos interesa que NO sea sensible a mayúsculas/minúsculas y que contenga (contains) la palabra o sección clave y de esta forma tener un filtro bastante flexible, pero puedes expresarlo como desees.

Descargar

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.