Menú de navegación lateral en iOS utilizando SWRevealViewController

jueves, 19 de marzo de 2015


Una característica habitual en la aplicaciones móviles es tener un menú de navegación lateral. La aplicación de Facebook fue la primera que mostró este tipo de menú. Vamos a ver en este artículo un ejemplo de cómo crear un menú lateral utilizando la librería SWRevealViewController.

Instalación de la libería

La libería consta de un fichero .h y otro .m con varias clases definidas en esos ficheros. Para instalar la librería podemos descargarla directamente de GitHub y copiamos los ficheros SWRevealViewController.h y SWRevealViewController.m. También existe la opción de añadir la librería a nuestro proyecto mediante Cocoapods.

Ejemplo

Para explicar como funciona SWRevealViewController voy a hacer un ejemplo muy sencillo que va a constar de un menú de navegación con 3 menús y al selecionar cada uno de ellos se abre su correspondiente view controller frontal.



Voy a utilizar en este ejemplo xib y no StoryBoard.

creando ViewController para el menú lateral

Para el menú lateral creamos un ViewController que herede de UIViewController y en el xib añadimos un TableView, el controlador tiene que implementar el protocolo de UITableViewDelegate y UITableViewDataSource. Ahora desde el xib pulsando ctrl arrastramos desde el TableView a File's Owner y seleccionamos las opciones de delegate y dataSource para indicar al TableView que el controlador es su datasource y delegate.

Implementando el protocolo DataSource

Al indicar que el controlador es el origen de datos, el TableView nos va a pedir información como número de filas o celdas, estos son dos métodos que tenemos que implementar obligatoriamente para cumplir el protocolo DataSource.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 3;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    NSInteger row = indexPath.row;
    
    if (nil == cell)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    
    NSString *text = nil;
    if (row == 0)
    {
        text = @"Blue View Controller";
    }
    else if (row == 1)
    {
        text = @"Red View Controller";
    }
    else if (row == 2)
    {
        text = @"Yellow View Controller";
    }
    
    cell.textLabel.text = text;
    
    return cell;
}


En nuestro caso vamos a tener 3 filas a modo de menús para navegar a cada uno de nuestros controllers.

Implementando el protocolo Delegate

Como delegado de TableView no es obligatorio implementar nigún método pero en nuestro caso como queremos navegar a una pantalla al pulsar sobre un menú de navegación, necesitamos implementar el método didSelectRowAtIndexPath y como parámetro nos va a venir la fila de la tabla seleccionada.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //Recuperamos el view controller contenedor reveal
    SWRevealViewController *revealController = self.revealViewController;
    
    // selecting row
    NSInteger row = indexPath.row;
    
    if ( row == _presentedRow )
    {
        [revealController setFrontViewPosition:FrontViewPositionLeft animated:YES];
    }
    else
    {
    UIViewController *newFrontController = nil;
    
    if (row == 0){
        BlueViewController *blue = [[BlueViewController alloc] init];
        newFrontController = [[UINavigationController alloc] initWithRootViewController:blue];
    }
    
    else if (row == 1){
        RedViewController *red = [[RedViewController alloc] init];
        newFrontController = [[UINavigationController alloc] initWithRootViewController:red];
    }
    else if ( row == 2 )
    {
        YellowViewController *yellow = [[YellowViewController alloc] init];
        newFrontController = [[UINavigationController alloc] initWithRootViewController:yellow];
    }
    
    [revealController pushFrontViewController:newFrontController animated:YES];
    
    _presentedRow = row;
    }
}


Lo primero que necesitamos hacer es acceder a nuestro parent RevealViewController, esta propiedad es una categoría que añade la librería al tipo UIViewController, será sobre el que tenemos que hacer push del controller al que queremos navegar. La idea es la misma que cuando el parent de un controlador es un UINavigationCotroller.

En caso de que la fila seleccionada sea la misma que el controller frontal que ya está abierto, invocamos el método setFrontViewPosition para ocultar el menú lateral y en caso contrario navegamos al controller adecuado según el menú seleccionado.

creando los ViewControllers frontales

Los ViewControllers frontales que vamos a tener en este ejemplo son iguales y lo único que cambia es el color de fondo, que se asigna en el xib, y el título.

#import "BlueViewController.h"
#import "SWRevealViewController.h"

@implementation BlueViewController


- (void)viewDidLoad{
    [super viewDidLoad];

    self.title = @"Blue View";

    [self configureSideMenuButton];
}

- (void)configureSideMenuButton{

    SWRevealViewController *revealController = [self revealViewController];

    [self.view addGestureRecognizer:revealController.panGestureRecognizer];

    UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Menu-icon.png"]
                                                                         style:UIBarButtonItemStylePlain target:revealController action:@selector(revealToggle:)];

    
    self.navigationItem.leftBarButtonItem = revealButtonItem;
}
@end


Básicamente lo único que hace este ViewController es asignar el título y crear un botón para el menú que asignaremos como botón izquierdo de la barra de navegación. Aquí lo importante es utilizar la propiedad revealViewController para acceder al parent y que como ya vimos al crear el menú lateral en la anterior sección esta propiedad es añadida mediante una categoría de la libreria SWRevealViewController. Por un lado configuramos el GestureRecognizer añadiendo el panGestrureRecognizer del parent y al botón le indicamos que su target es el parent revealViewController y el método revealToggle para que se invoque al pulsar el botón. Estas dos configuraciones va a hacer que al pulsar el botón o arrantrar el desde desde la parte izquierda aparezca nuestro menú lateral.

Creando el contenedor principal SWRevealControler

Una vez creados los ViewController frontales y el lateral, ahora necesitamos crear el SWRevealControler en el AppDelegate, este controlador va a ser el controlador principal que va a contener el menú lateral y el controlador frontal de inicio o por defecto. Pero no va a contenerlos directamente, como necesitamos navegar a cada uno de los controladores frontales desde el menú lateral necesitamos un UINavigationViewController como root de la parte lateral y también necesitamos un UINavigationViewController como root de la parte frontal porque necesitamos una barra de navegación donde poner nuestro botón menú para visualizar el menú lateral. Este UINavigationViewController además nos va a permitir navegar a otros controladores que no están contenidos dentro del SWRevealControler.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];

    SideViewController *sideMenuViewController = [[SideViewController alloc] init];
    BlueViewController *blueViewController = [[BlueViewController alloc] init];
    
    UINavigationController *frontNavigationController = [[UINavigationController alloc] initWithRootViewController:blueViewController];
    UINavigationController *rearNavigationController = [[UINavigationController alloc] initWithRootViewController: sideMenuViewController];
    
    SWRevealViewController *mainRevealController = [[SWRevealViewController alloc]
                                                    initWithRearViewController:rearNavigationController frontViewController:frontNavigationController];
    
    self.window.rootViewController = mainRevealController;
    
    [self.window makeKeyAndVisible];
    
    return YES;
}


Código fuente disponible en GitHub.

Resumen

En este artículo hemos visto como crear un menú de navegación lateral utilizando la librería SWRevealViewController que nos simplifica bastane la creación de este tipo de menú.

Libros relacionados

NSHipster: Obscure Topics in Cocoa & Objective C

iOS Programming: The Big Nerd Ranch Guide

Objective-C Programming: The Big Nerd Ranch Guide

No hay comentarios:

Publicar un comentario