inicio

Crea un buscador en Android: AutoCompleteTextView

Buenas, esta semana volvemos a la programación Android despues de estar instalando la semana pasada un servidor GIT. Vamos a ver como utilizar el control AutoCompleteTextView para construir un buscador que nos vaya dando resultados a medida que escribimos nuestra búsqueda. El buscador va a ir haciendo consultas a una base de datos que previamente hemos creado e insertado datos en nuestra aplicación.



Lo primero que vamos a hacer es crear las 2 vistas que necesitaremos. La primera de ellas es la que tiene el control AutoCompleteTextView y la otra muestra cada uno de los resultados de la búsqueda.
Este es el código del primer archivo, le llamaremos bar_search.xml. He puesto el control y su etiqueta  en un LinearLayout y este a su vez en un RelativeLayout de esta forma podemos hacer que el LinearLayout y su contenido flote en la parte de la pantalla que querais, jugando con los parámetros layout_alignParentTop, Bottom, Left, Right y con los margin y padding.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout style="@style/SearchBar" android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView text="Buscar" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<AutoCompleteTextView android:id="@+id/txtSearch"android:layout_width="fill_parent" android:layout_height="fill_parent" />
</LinearLayout>
</RelativeLayout>


Este es el código del segundo archivo, le llamaremos item_search.xml. Este será el que nos de el diseño para cada uno de los items encontrados que nos vaya mostrando el control de autocompletado.


<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/lblItemSearch"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16sp"
android:textColor="#000">
</TextView>


Una vez que ya tenemos listas las vistas vamos a crear una clase para gestionar la base de datos. Ya hemos visto como hacer esto en otros artículos os dejo el enlace aquí: como guardar datos en base de datos android. En el ejemplo de ese artículo habíamos creado una clase bbdd, la cual retomaremos para añadir un método que será el que va a buscar los resultados, en este caso vamos a buscar en la tabla de libros. El código del método será el siguiente:


public Cursor getCursorBuscador(String textSearch){
textSearch = textSearch.replace("'", "''");
SQLiteDatabase db = getReadableDatabase();
return db.rawQuery("SELECT id_libro AS _id, nombre AS item" +
" FROM "+TableLibros +
" WHERE nombre LIKE '%" +textSearch+ "%' ", null);
}


El método que añadimos, getCursorBuscador, va a buscar en la tabla libros. Con la instrucción LIKE y los % (caracter comodin) buscamos todos aquellos libros que contengan en su nombre el texto que hemos introducido. En la primera línea hacemos un replace de una comilla simple por dos comillas simples, de lo contrario al hacer una búsqueda que contenga este carácter daría error. El replace lo pongo en este método para simplificar. Lo mejor sería hacerse un método para esto y aplicarlo en todas las consultas a base de datos que se necesite.


También es bastante importante el alias _id que se le da a la columna id_libro ya que el CursorAdapter que utilizaremos más adelante espera que en el cursor de datos exista esta columna que identificará cada uno de los items con este nombre.


Lo siguiente que vamos a hacer es una clase para gestionar el acceso a datos desde el AutoCompleteTextView, le llamaremos CursorAdapterSearch y va a heredar de CursorAdapter.


public class CursorAdapterSearch extends CursorAdapter {

private bbdd db;

public CursorAdapterSearch(Context context, Cursor c) {
super(context, c);
db = new bbdd(context);
}

@Override
public void bindView(View view, Context arg1, Cursor cursor) {
String item = createItem(cursor);
((TextView ) view).setText(item);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
final LayoutInflater inflater = LayoutInflater.from(context);
final TextView view = (TextView) inflater.inflate(R.layout.item_search, parent, false);

String item = createItem(cursor);
view.setText(item);

return view;
}

@Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
Cursor currentCursor = null;

if (getFilterQueryProvider() != null) {
return getFilterQueryProvider().runQuery(constraint);
}

String args = "";

if (constraint != null) {
args = constraint.toString();
}

currentCursor = db.getCursorBuscador(args);

return currentCursor;
}

private String createItem(Cursor cursor){
String item = cursor.getString(1);
return item;
}
}


Como os decía, con esta clase gestionaremos el acceso a los datos del AutoCompleteTextView. Estamos leyendo de una base de datos, pero el control también podría por ejemplo conectarse a un servicio web que nos devolviera el resultado de búsqueda. En esta clase hay que destacar como sobrescribimos el método runQueryOnBackgroundThread, en el que args es el texto que va introduciendo el usuario y se lo pasamos al objeto db para llamar a getCursorBuscador que nos devuelve un objeto Cursor que es el que finalmente devuelve.


Ahora vamos a crear una clase que será la que va a gestionar la vista del buscador y que al final pondremos en aquellas pantallas donde queremos utilizarlo. Vamos a crear una clase llamada BarSearch y que hereda de RelativeLayout.


public class BarSeach extends RelativeLayout {

private Activity activity;
private AutoCompleteTextView txtSearch;
private CursorAdapterSearch CategoriesAdapter;
private Cursor mCursor;
private bbdd db;

public BarSeach(Activity activity) {
super(activity);
this.activity = activity;

String infService = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater li = (LayoutInflater)getContext().getSystemService(infService);
li.inflate(com.trespies.guia.generic.R.layout.bar_search, this, true);

db = new bbdd(this.activity);
mCursor = db.getCursorBuscador("");

this.activity.startManagingCursor(mCursor);
CategoriesAdapter = new CursorAdapterSearch(this.activity, mCursor);

txtSearch = (AutoCompleteTextView) findViewById(R.id.txtSearchPOIs);
txtSearch.setAdapter(CategoriesAdapter);
txtSearch.setThreshold(1);

txtSearch.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3) {
Cursor c = (Cursor) arg0.getAdapter().getItem(position);
txtSearch.setText(c.getString(1));

int id = c.getInt(0);
String t = c.getString(1);

ListenerItemClickSearch.onItemClickSearchListener(id, t);
}

});
}

public interface OnItemClickSearchListener{
void onItemClickSearchListener(int idItem, String texto);
}

private OnItemClickSearchListener ListenerItemClickSearch;

public void setOnItemClickSearchListener(OnItemClickSearchListener l){
ListenerItemClickSearch = l;
}

}


En esta clase, hacemos la mayor parte del proceso en el constructor. Primero se inicializa el layout que creamos al principio. Inicializamos un objeto Cursor, pasamos el control (con startManagingCursor) a la Activity para que sea esta la que se encargue de desactivarlo si salimos de ella, y creamos un objeto CursorAdapterSearch al que le pasamos este cursor que será el que maneje.


Después inicializamos el AutoCompleteTextView, seteamos su Adapter con el objeto CursorAdapterSearch. Con setThreshold le decimos cuantos caracteres hay que escribir para que empiece a buscar. Esto debéis setearlo según lo grande que sea el conjunto de datos sobre el que buscamos y lo que va a tardar en hacer la búsqueda, cuanto más datos, más caracteres deberíamos esperar (pero tampoco sin pasarnos, intentad buscar un termino medio).


Por último, seteamos el evento click de cada uno de los resultados, en este para obtener los  datos del item sobre el que hemos hecho click utilizamos el primer parámetro del evento. Con arg0.getAdapter() accedemos al conjunto entero de datos y con getItem y position obtenemos el item seleccionado. Como este cursor tiene los datos de nuestra consulta, podemos acceder a los datos con getInt, getString y su posición correspondiente. Por último, lanzamos el evento ItemClickSearch que nosotros mismos definimos en esta clase.

El evento OnItemClickSearch definido por nosotros nos va a servir para saber desde fuera de nuestra clase cuando se hace click sobre uno de los resultados de la búsqueda. Este lo llamaremos en las Activitys en las que utilicemos nuestra clase para realizar diferentes acciones según nuestras necesidades. El evento nos va a dar el id del item y el texto del item seleccionado, pero podéis poner más parámetros según las necesidades de vuestra aplicación.


Para terminar, vamos a utilizar el buscador en una de nuestras Activitys, para ello, abrimos una Activity de nuestro proyecto y en el método OnCreate añadimos el siguiente código:


BarSearch search = new BarSeach(this);
search.setOnItemClickSearchListener(new OnItemClickSearchListener() {
public void onItemClickSearchListener(int idItem, String texto) {
//Aquí va el código que se ejecutará en cada caso al hacer click en un item
}
});
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
addContentView(search, lp);


Como veis, su utilización final es bastante sencilla, simplemente hemos de crear un objeto BarSearch, setear que es lo que hará en el ItemClickSearch y añadirlo a la vista de nuestra Activity. El objeto LayoutParams es necesario para darle por lo menos un alto y un ancho, ya que sino lanzará una excepción.
The following two tabs change content below.
Técnico en Administración de Sistemas y Desarrollo de Aplicaciones. Amigo de sus amigos, y una mente inquieta que no puede dejar un ordenador de lado porque necesita programar aplicaciones Android o aplicaciones en general, además de páginas web. Nuestro programador de cabecera y espero que también el vuestro.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. ACEPTAR

Aviso de cookies