Barras de búsqueda en iOS

Seguramente en muchas de nuestras aplicaciones de iOS hemos tenido que mostrar una tabla de datos con un montón de entradas. Desde el punto de vista del usuario, es bastante molesto tener que buscar el elemento que quiere entre todos los elementos.

Para mejorar la usabilidad, se plantean varias alternativas. Podemos separar los datos en varios niveles, de tal manera que dividamos los datos en varios bloques, sin embargo, esta solución tiene como inconveniente que obligamos a navegar por varias pantallas.

Concretamente en iOS tenemos varias alternativas para «ordenar» nuestros datos a nivel visual. Podemos crear listas por secciones e incluso incluir un indice para saltar entre los diferentes datos al mas puro estilo iTunes o la aplicación que muestra los Contactos.

Sin embargo, aunque ayuda, no acaba de solucionar el problema de tener que buscar la entrada que queremos en nuestra tabla.

Aquí es donde entra el campo de búsqueda que seguro habéis visto en numerosas aplicaciones de iOS como Facebook, Twitter o iTunes. En esta entrada vamos a ver como añadir una barra de búsqueda a nuestra aplicación.

Dentro del conjunto de controles estándar de iOS, tenemos la clase UISearchBar, que representa el cuadro de texto con esquinas redondeadas y la lupa a la que estamos acostumbrados. Sin embargo, este elemento es solo la parte gráfica del sistema de búsqueda. Además de esta clase, vamos a necesitar tratar con la clase UISearchDisplayController, que será la que enlazada a los ViewControllers habituales, nos van a proporcionar todo el sistema de búsqueda que hemos visto en las aplicaciones antes comentadas.

Esta instancia de UISearchDisplayController no vive sola, la mayoría de nuestras vistas, están gestionadas por una clase «Controller» que hereda de UIViewController, en esta clase esta definida una propiedad llamada searchDisplayController, a la que podemos asignar nuestra clase controladora del campo de búsqueda. Haciendo esto ganamos bastante funcionalidad.

Si hemos visto el funcionamiento de la barra de búsqueda, hemos visto como al tocar para introducir texto, esta barra se coloca en la parte superior de forma animada, sombreando además la vista entera, además, en algunos casos salen unos botones debajo de la barra de búsqueda, que indican donde se esta realizando la búsqueda. Pues bien, todo este comportamiento esta «de propina» si asignamos la propiedad del ViewController a nuestro SearchController.

Para llevar esto a la práctica, suponiendo que tenemos un proyecto con un NavigationController, tenemos que ir a la vista que se carga como contenido del navigation controller y añadir el SearchViewController.

Automáticamente XCode asigna los outlets, pero para saber como funciona, no es mala idea cotillearlos un poco. XCode establece el outlet del UINavigationController llamado searchDisplayController al SearchDisplayController que acabamos de añadir a la vista. Normalmente el NavigationController será el File’s Owner del fichero, y así lo vemos en la captura de un poco más arriba.

Hasta ahora, solo hemos hablado de la parte visual, pero después de crear el SearchDisplayController y asignarlo a la propiedad en el ViewController, si introducimos texto, vemos como no pasa nada. El siguiente paso consiste en decir como vamos a mostrar los datos de la búsqueda.

Para mostrar los datos, una de nuestras clases tiene que implementar varios protocolos habituales de una UITableView, como son UITableViewDataSource y UITableViewDelegate. Como veis, al fin y al cabo el proceso se reduce a mostrar una vista reducida de nuestros datos, filtrada por la condición de búsqueda.

Como vemos en la captura anterior, los outlets del SearchDisplay controller respecto al origen de los datos, esta establecidos al File’s Owner.

En cuanto a la estrategia de implementación, se pueden seguir varias aproximaciones. Por un lado se puede hacer que la misma clase sea DataSource de ambas tablas, es decir, la tabla con todos los datos y la tabla con los datos de la búsqueda, sin embargo esta solución tiene el problema que los mismos métodos tienen que devolver cosas diferentes. Personalmente no me gusta nada esta solución.

Por otro lado, se pueden tener dos clases diferentes, sin embargo hay que tener en cuenta que el modelo de datos a la que acceden ambas clases, es compartido, ya que la búsqueda se realiza sobre los datos que esta mostrando el ViewController de turno.

Estas dos alternativas están pensadas a cuando la búsqueda se realiza sobre una tabla de datos, sin embargo, no tiene por que ser siempre así, la búsqueda podemos hacerla sobre cualquier vista que queramos. En tal caso no habrá mucho problema en unir en la misma clase que gestiona la vista, los métodos de gestión de la tabla de los resultados de la búsqueda.

A continuación os pongo el código de una implementación, el código no pretende ser eficiente, si no mostrar el funcionamiento 😉

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    [filteredData release];
    filteredData = [[NSMutableArray alloc] init];
    for ( NSString* name in tableData )
    {
        if ([[name lowercaseString] rangeOfString:[searchText lowercaseString]].location != NSNotFound )
            [filteredData addObject:name];
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [filteredData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if ( cell == nil )
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    
    cell.textLabel.text = [filteredData objectAtIndex:indexPath.row];
    return cell;
}

Ya que mucha parte del funcionamiento, esta embebido en los ficheros de Interface Builder, he subido el proyecto de prueba a github, por si alguien quiere echarle un ojo.

2 Responses to Barras de búsqueda en iOS

  1. José Antonio dice:

    Hola Roberto, he seguido tu tutorial pero tengo ahora varias dudas:
    Necesito modificar la tableView para que muestre los resultados de la búsqueda como yo quiero en vez del resultado por defecto,es decir, personalizar el tableViewCell. Ésto se haría en el método cellForRowAtIndexPath supongo, estoy usando storyBoard.
    ¿Cómo hago para cargar un modelo de tabla personalizado? Me creo un archivo .xib con una tabla y personalizo el tableViewCell?, o me creo una viewController nueva con una tabla en el storyBoard y lo cargo en el método cellForRowAtIndexPath ?

    Otra forma que se me ocurre es que la clase searchAssistant en vez de ser de tipo NSObject sea de tipo viewController y crear un xib o añadirla al storyBoard, pero luego tengo problemas con las conexiones en el IB.

    Quiere hacer todo esta para poder además, añadir el método de selectRowAtIndexPath y que me lleve a otra vista detail al seleccionar una celda..

    Espero haberme explicado bien.

    Nada más, solo agradecerte el trabajo que has hecho con este tutorial, un saludo.

  2. Hello, everything is going fine here and ofcourse every one is sharing facts, that’s actually excellent, keep up writing.

Deja un comentario