Ejemplo de tutorial de SearchView en Android usando DataBinding

Hoy vamos a analizar el widget Android SearchView y desarrollar una aplicación que filtre un ListView por el texto consultado. Utilizaremos DataBinding para conectar los diseños en las actividades y adaptadores. Si aún no has leído sobre DataBinding, consulta primero este tutorial para entenderlo mejor.

Android SearchView

Android nos permite utilizar la funcionalidad de búsqueda en nuestra aplicación mostrando el widget SearchView ya sea en la Barra de herramientas/ActionBar o insertándolo en un diseño. El widget Android SearchView está disponible desde Android 3.0 en adelante. El SearchView se define en el diseño XML como se muestra a continuación.

<android.support.v7.widget.SearchView
        android:id="@+id/search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

Existen muchas formas de búsqueda en Android, como la búsqueda por voz, sugerencias, etc. En este tutorial utilizaremos las interfaces SearchView.OnQueryTextListener y Filterable. La interfaz Filterable filtra el texto consultado sobre un ListView y muestra las filas resultantes del ListView. La interfaz OnQueryTextListener puede detectar dos eventos.

  1. onQueryTextChange se llama cuando el usuario escribe cada carácter en el campo de texto
  2. onQueryTextSubmit se activa cuando se presiona la búsqueda

Ejemplo de SearchView en Android

La siguiente imagen muestra el proyecto final de ejemplo de SearchView en Android. El proyecto consta de una Actividad y un Adaptador para el ListView.

Código de ejemplo de SearchView en Android

El archivo activity_main.xml se muestra a continuación. Consiste en un ListView con un SearchView en la parte superior. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <android.support.v7.widget.SearchView
            android:id="@+id/search"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clickable="true" />

        <ListView
            android:id="@+id/list_view"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/search" />

    </RelativeLayout>

</layout>

El archivo MainActivity.java se muestra a continuación.

package com.journaldev.searchview;

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;

import com.journaldev.searchview.databinding.ActivityMainBinding;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    ActivityMainBinding activityMainBinding;
    ListAdapter adapter;

    List<String> arrayList= new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        arrayList.add("January");
        arrayList.add("February");
        arrayList.add("March");
        arrayList.add("April");
        arrayList.add("May");
        arrayList.add("June");
        arrayList.add("July");
        arrayList.add("August");
        arrayList.add("September");
        arrayList.add("October");
        arrayList.add("November");
        arrayList.add("December");

        adapter= new ListAdapter(arrayList);
        activityMainBinding.listView.setAdapter(adapter);

        activityMainBinding.search.setActivated(true);
        activityMainBinding.search.setQueryHint("Type your keyword here");
        activityMainBinding.search.onActionViewExpanded();
        activityMainBinding.search.setIconified(false);
        activityMainBinding.search.clearFocus();

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

            @Override
            public boolean onQueryTextChange(String newText) {

                adapter.getFilter().filter(newText);

                return false;
            }
        });
    }
}

En el código anterior, estamos pasando un ArrayList de meses al Adaptador de Lista. Estamos invocando el método de filtro que está definido en la clase del adaptador cada vez que cambia el texto de la consulta de búsqueda. La clase ListAdapter.java se ve así.

package com.journaldev.searchview;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.journaldev.searchview.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;

public class ListAdapter extends BaseAdapter implements Filterable {

    List<String> mData;
    List<String> mStringFilterList;
    ValueFilter valueFilter;
    private LayoutInflater inflater;

    public ListAdapter(List<String> cancel_type) {
        mData=cancel_type;
        mStringFilterList = cancel_type;
    }


    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public String getItem(int position) {
        return mData.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, final ViewGroup parent) {

        if (inflater == null) {
            inflater = (LayoutInflater) parent.getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }
        RowItemBinding rowItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
        rowItemBinding.stringName.setText(mData.get(position));


        return rowItemBinding.getRoot();
    }

    @Override
    public Filter getFilter() {
        if (valueFilter == null) {
            valueFilter = new ValueFilter();
        }
        return valueFilter;
    }

    private class ValueFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (constraint != null && constraint.length() > 0) {
                List<String> filterList = new ArrayList<>();
                for (int i = 0; i < mStringFilterList.size(); i++) {
                    if ((mStringFilterList.get(i).toUpperCase()).contains(constraint.toString().toUpperCase())) {
                        filterList.add(mStringFilterList.get(i));
                    }
                }
                results.count = filterList.size();
                results.values = filterList;
            } else {
                results.count = mStringFilterList.size();
                results.values = mStringFilterList;
            }
            return results;

        }

        @Override
        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            mData = (List<String>) results.values;
            notifyDataSetChanged();
        }

    }

}

Como puede ver en el código anterior, estamos realizando filtrado usando una clase interna ValueFilter que extiende la clase Filter. Filtra la lista comprobando si el texto de la consulta de búsqueda coincide con las cadenas dadas en el ArrayList. El diseño XML para la fila del ListView se muestra a continuación. row_item.xml

<layout xmlns:android="https://schemas.android.com/apk/res/android">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/stringName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:padding="@dimen/activity_horizontal_margin"
            android:textAllCaps="false"
            android:textAppearance="?android:attr/textAppearanceMedium" />

    </RelativeLayout>

</layout>

La salida de la aplicación Android SearchView en acción se muestra a continuación. El SearchView mostrado anteriormente requiere que presionemos el ícono de búsqueda para activar el campo de texto. Además, no contiene ningún texto de pista/placeholder. Agregue el siguiente código en MainActivity para habilitar el SearchView por defecto y mostrar una pista.

activityMainBinding.search.setActivated(true);
        activityMainBinding.search.setQueryHint("Type your keyword here");
        activityMainBinding.search.onActionViewExpanded();
        activityMainBinding.search.setIconified(false);
        activityMainBinding.search.clearFocus();

El SearchView después de personalizarlo como se describe se ve así. Esto concluye el tutorial de Android SearchView. Nos sumergiremos en las funciones avanzadas de SearchView en un tutorial posterior. Puedes descargar el Proyecto Android SearchView desde el enlace proporcionado a continuación.

Descargar el Proyecto de Ejemplo Android SearchView

Source:
https://www.digitalocean.com/community/tutorials/android-searchview-example-tutorial