Aplicación Android Con Navigation Drawer Y Tabs

En este artículo aprenderás a crear una aplicación Android que contenga Navigation Drawer y Tabs de forma conjunta. La idea es crear secciones con diferentes fragmentos y ver como introducir una gran variedad de layouts.

El ejemplo que verás se trata de una aplicación que ofrece a los usuarios diferentes platos de comida pertenecientes a un restaurante hipotético llamado “Rico Pa’ Rico”.

Crearemos cuatro secciones del navigation drawer para comprobar cómo se sortean situaciones similares a estas:

  • Un navigation drawer con fragmentos diferentes.
  • Un navigation drawer con tabs.
  • Listas y grid views en tabs.
  • Tabs con fragmentos diferentes.
  • Iniciar una actividad de configuración desde un navigation drawer.

Si sigues leyendo podrás obtener un resultado similar a este:

Para ver el link de descarga del proyecto completo en Android Studio, sigue estas instrucciones:

#1. Planeación De Pantallas Y Sus Relaciones

Antes de comenzar con el desarrollo, conozcamos un poco más de la app.

Con la aplicación móvil Rico Pa’ Rico se pretende mostrar:

  • Un inicio con los productos más populares entre los clientes del restaurante.
  • Los datos de la cuenta del usuario como su perfil, las direcciones que tiene asociadas para la entrega de productos a domicilio y la información de las tarjetas que ha usado para pagos.
  • También se necesita mostrar el menú de comidas divididos en tres categorías: Platillos, Bebidas y Postres. Sería ideal mostrar el precio y el nombre más una pequeña imagen de la comida.
  • Posibilitar la configuración del envío de correos informativos a la cuenta del usuario. Las frecuencias de envío son: diario, semanal, mensual o sin envío.

Básicamente esos son los requerimientos de la app. Como ves, hacen falta varias funcionalidades para tener un servicio a domicilio completo, sin embargo, estas características permitirán entender a la perfección el uso de un navigation drawer y tabs.

A partir de los requerimientos se deduce que se necesita la siguiente lista de pantallas:

  • Menú principal para las secciones disponibles
  • Inicio con una lista de los elementos populares
  • Sección para los datos de la cuenta
  • Sección para las categorías
  • Pantalla de configuración de notificaciones
  • Detalle del perfil del usuario
  • Lista de direcciones
  • Lista de tarjetas o pantalla con aviso en blanco
  • Grilla de platillos
  • Grilla para bebidas
  • Grilla para postres

Ahora representemos las relaciones entre pantallas a través de un mapa relacional. La idea es mostrar los posibles accesos desde una pantalla hacia otra.

Screen Map De Aplicación Android

El siguiente paso es decidir los patrones convenientes para representar la estructura del mapa anterior. Es aquí donde encaja el patrón del Navigation Drawer.

¿Pero por qué usar un navigation drawer en esta aplicación?

Porque existen algunas secciones que tienen dos niveles de navegación o incluso la forma en que estaría organizado el modelo de datos de esta aplicación muestra subdivisión en los datos.

En ese caso la documentación de Material Design sugiere añadir este elemento como primer nivel y dejar en segundo nivel las subcagtegorías a través de tabs.

Navegación En Material Design Con Navigation Drawer

En primer nivel estarían cuatro categorías principales asociadas al funcionamiento de la aplicación como lo son Inicio, Mi Cuenta, Categorías (o Menú) y Configuración.

Dentro de la cuenta podemos crear varias subdivisiones entre el perfil, las direcciones y las tarjetas. Este sería un segundo nivel.

Al igual que en categorías, donde encontramos valga la redundancia, tres subcategorías para segmentar.

Teniendo esto claro, dentro del mapa de pantallas podemos reemplazar los elementos Menú Principal, Mi Cuenta y Categorías por los patrones necesarios.

Patrones En Screen Map De Aplicación Android

#2. Wireframe Aplicación Android

El segundo paso es bocetar las ideas generales de funcionalidad que tenemos. Para ello usaré una aplicación online gratuita para crear wireframes de apps móviles llamada Ninja Mock.

Su funcionamiento es sencillo. Simplemente te registras y luego abres tu escritorio de apps. Una vez allí presionas New Project para crear un nuevo proyecto.

New Project Ninja Mock

En seguida seleccionas la categoría ANDROID.

Android WireFrame NinjaMock

Y con ello se abrirá tu espacio de trabajo para que realices los diseños necesarios. Tendrás a disposición gran variedad de elementos visuales en el panel izquierdo, así como la posibilidad de editar sus propiedades en el panel derecho.

Workspace En Ninja Mock

Sin embargo este apartado no es un tutorial sobre ninja mock. Espero esta introducción te facilite probar sus funcionalidades.

 

Nota: Si quieres aprender más sobre wireframing y diseño de apps móviles, entonces te recomiendo tomar el curso Curso de diseño de aplicaciones para iOs y Android.

Basado en el mapa de pantallas con patrones definidos de la anterior sección, el boceto de nuestra app quedaría de la siguiente forma:

Wireframe Aplicacion Android Con Navigation Drawer

Ahora lo que sigue es crear cada uno de los componentes gráficos necesarios para generar la aplicación.

#3. Navigation Drawer Con Diferentes Fragmentos

Cada una de las pantallas de nuestra aplicación será contenida en una serie de fragmentos relacionados dentro del navigation drawer.

Solo tendremos dos actividades para manejar la estructura completa. Una actividad principal y la de ajustes o configuración.

Comencemos…

1. Abre Android Studio y crea un nuevo proyecto llamado “Restaurante Rico Pa Rico”. Añade por defecto una actividad en blanco con el nombre ActividadPrincipal.java y confirma.

2. Prepara las características mínimas del proyecto para su funcionamiento. Define la paleta de colores para material design dentro de tu archivo colors.xml de la siguiente forma:

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="window_background">#ffffff</color>

    <color name="primaryDarkColor">#323232</color>
    <color name="primaryColor">#484848</color>
    <color name="accentColor">#F87652</color>

    <color name="background_footer_item_grid_categorias">#90000000</color>

    <color name="color_light">#ffffff</color>

    <color name="background_header_seccion_inicio">#4B4B4B</color>
</resources>

No te preocupes por los demás valores, ya que los usaremos más adelante.

Ahora añade los siguientes strings para la interfaz.

strings.xml

<resources>
    <string name="app_name">"Restaurante Rico Pa Rico "</string>

    <string name="action_settings">Configuración</string>
    <string name="action_search">Buscar</string>
    <string name="action_carrito">Añadir al carrito</string>

    <string name="item_inicio">Inicio</string>
    <string name="item_cuenta">Mi Cuenta</string>
    <string name="item_categorias">Categorías</string>
    <string name="item_configuracion">Configuración</string>

    <string name="titulo_comidas_populares">Lo más pedido</string>

    <string name="titulo_tab_platillos">PLATILLOS</string>
    <string name="titulo_tab_bebidas">BEBIDAS</string>
    <string name="titulo_tab_postres">POSTRES</string>

    <string name="titulo_tab_perfil">PERFIL</string>
    <string name="titulo_tab_direcciones">DIRECCIONES</string>
    <string name="titulo_tab_tarjetas">TARJETAS</string>

    <string name="texto_no_tarjetas">No tienes ninguna tarjeta asociada</string>

    <string name="etiqueta_carrito">Carrito</string>

    <string name="texto_cambiar_contrasena">Cambia tu contraseña</string>
    <string name="etiqueta_contrasena">Contraseña</string>
    <string name="etiqueta_info_usuario">Información del usuario</string>

</resources>

Importante declarar los estilos que usaremos. En nuestro caso tendremos dos estilos. Uno para la actividad principal, la cual usará el navigation drawer y requiere transparencia. Y otro para la actividad configuración, la cual usa el estilo por defecto.

styles.xml

<resources>

    <style name="Theme.RicoPaRico" parent="Base.AppTheme" />

    <style name="Base.AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryDark">@color/primaryDarkColor</item>
        <item name="colorAccent">@color/accentColor</item>

        <item name="android:windowBackground">@color/window_background</item>
    </style>

    <style name="Theme.ConNavigationDrawer" parent="Base.AppTheme"/>
</resources>

Para versiones menores a 21, los atributos de transparencia no son soportados, por lo que dejamos el tema Theme.ConNavigationDrawer vacío. Sin embargo, en versiones mayores o iguales a 21 si requeriremos completar este estilo.

values-21/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.RicoPaRico" parent="Base.AppTheme">
    </style>

    <style name="Theme.ConNavigationDrawer" parent="Base.AppTheme">
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

Por último añade las dependencias de las librerías que usaremos en el proyecto. Debido al tipo de estilo visual que usaremos, requeriremos la nueva librería de diseño, el uso de glide para carga de imágenes, la extensión de recycler view y cardview.

build.gradle

dependencies {
    ...
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
    compile 'com.android.support:recyclerview-v7:23.0.1'
    compile 'com.github.bumptech.glide:glide:3.6.1'
    compile 'com.android.support:support-v4:23.0.1'
    compile 'com.android.support:cardview-v7:23.0.1'
}

¡Ah! y muy importante, descarga los drawables del proyecto para completar la interfaz. A continuación el link de descarga.

3. Abre el layout de la actividad principal (en mi caso se llama actividad_principal.xml) y elimina su diseño por defecto para comenzar a construir uno basado en un navigation drawer.

Para tener una guía observaremos el diseño del wireframe bocetado anteriormente:

Wireframe De App Android Con Navigation Drawer

En este caso, es un navigation drawer con cabecera. Solo tiene 4 ítems con las secciones estudiadas.

La cabecera contiene el logo de la empresa en la parte superior alineada a la izquierda y por debajo una doble línea que representa la cantidad existente dentro del carrito de compras (incluso tiene un icono en la parte izquierda para aclarar la idea).

La creación es sencilla como vimos en el artículo NavigationView: Navigation Drawer Con Material Design, donde el nodo principal es un elemento DrawerLayout. Cuyo contenido han de ser dos elementos.

El contenido principal, representado por cualquier elemento visual y un componente NavigationView (librería de soporte de diseño) para la parte deslizante con el menú.

actividad_principal.xml

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- Contenido Principal -->
    <include layout="@layout/contenido_principal" />

    <!-- Menú Deslizante -->
    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/cabecera_drawer"
        app:menu="@menu/menu_drawer" />

</android.support.v4.widget.DrawerLayout>

4. El header contenido principal lo declararemos en un layout externo llamado contenido_principal.xml. Dentro de él pondremos una estructura simple que contenga la App Bar con una Toolbar implementada y como contenedor principal irá un RelativeLayout, el cual será reemplazado por cada fragmento de las secciones.

contenido_principal.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    </android.support.design.widget.AppBarLayout>

    <RelativeLayout
        android:id="@+id/contenedor_principal"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

5. El header del navigation drawer lo crearemos en otro layout independiente llamado cabecera_drawer.xml. Básicamente necesitamos un linear layout que contenga una fila para el logo (ImageView) y otra para un TableLayout de 2×2 para ubicar el icono del carrito más la etiqueta y texto asociadas a las compras.

cabecera_drawer.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/primaryColor"
    android:gravity="bottom"
    android:orientation="vertical"
    android:padding="@dimen/padding_izquierdo_cabecera"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <!-- Logo Rico Pa' Rico -->
    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="@dimen/ancho_logo"
        android:layout_height="wrap_content"
        android:src="@drawable/logo" />

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:columnCount="2"
        android:orientation="vertical"
        android:rowCount="2">


        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/icono_carrito"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="8dp"
                android:src="@drawable/carrito_compras" />

            <TextView
                android:id="@+id/etiqueta_carrito"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="@string/etiqueta_carrito"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textStyle="bold" />

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/texto_total_carrito"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_column="1"
                android:layout_gravity="center_vertical"
                android:text="$ 0"
                android:textAppearance="@style/TextAppearance.AppCompat.Body1"
                android:textStyle="bold" />
        </TableRow>

    </TableLayout>
</LinearLayout>

6. Lo siguiente es construir un recurso del tipo menu para implementar las secciones del navigation drawer. Para ello crea un nuevo archivo llamado menu_drawer.xml.

Recuerda que tendremos las siguientes secciones o ítems: Inicio, Mi Cuenta, Categorías y Configuración.

menu_drawer.xml

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

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/item_inicio"
            android:checked="true"
            android:icon="@drawable/inicio"
            android:title="@string/item_inicio" />
        <item
            android:id="@+id/item_cuenta"
            android:icon="@drawable/cuenta"
            android:title="@string/item_cuenta" />
        <item
            android:id="@+id/item_categorias"
            android:icon="@drawable/categorias"
            android:title="@string/item_categorias" />
        <item
            android:id="@+id/item_configuracion"
            android:icon="@drawable/configuracion"
            android:title="@string/item_configuracion" />
    </group>

</menu>

7. Por último modifica la lógica de la actividad principal.

Cambia el home button por el icono del navigation drawer y luego controla el evento de apertura dentro de onOptionsItemSelected(). Recuerda que esto lo hacemos el método DrawerLayout.openDrawer().

ActividadPrincipal.java

package com.herprogramacion.restaurantericoparico.ui;

import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

import com.herprogramacion.restaurantericoparico.R;

public class ActividadPrincipal extends AppCompatActivity {

    private DrawerLayout drawerLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad_principal);

        agregarToolbar();

        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    }

    private void agregarToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        final ActionBar ab = getSupportActionBar();
        if (ab != null) {
            // Poner ícono del drawer toggle
            ab.setHomeAsUpIndicator(R.drawable.drawer_toggle);
            ab.setDisplayHomeAsUpEnabled(true);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_actividad_principal, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                drawerLayout.openDrawer(GravityCompat.START);
                return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Al ejecutar la aplicación tendrás algo como esto:

Ejemplo De Navigation Drawer En Android Con Material Design

#4. Sección De Navigation Drawer Con Fragmento De Lista

Siguiendo el orden, ahora es turno de crear la sección Inicio, al cual contiene una lista de las comidas más populares que tiene el restaurante. El boceto se ve así:

Wireframe De Fragmento Con RecyclerView

Abordar este diseño es fácil para nosotros, ya que sabemos muy bien cómo usar el RecyclerView para crear listas pobladas por adaptadores.

Básicamente necesitamos:

  • La clase Fragment para el contenido.
  • Un layout para el fragmento.
  • Un modelo de datos.
  • Un layout para los ítems.
  • Un adaptador para el recycler view.

Así que manos a la obra.

1. Añade un nuevo fragmento en blanco al proyecto llamado FragmentoInicio.java. Recuerda que puedes hacerlo a través del asistente File > New > Fragment > Fragment (Blank).

New Blank Fragment En Android Studio

2. Abre el layout asignado el fragmento. En mi caso se llama fragmento_inicio.xml. La idea es añadir un encabezado inicial con el texto "Lo más pedido" y por debajo un recycler view que muestre la lista de elementos.

fragmento_inicio.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:background="@color/background_header_seccion_inicio"
        android:gravity="center"
        android:padding="8dp"
        android:text="@string/titulo_comidas_populares"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"
        android:textColor="@color/color_light" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/reciclador"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />
</LinearLayout>

3. Crea una nueva clase Java llamada Comida. Su objetivo es representar cada comida que mostraremos a través de la aplicación, es decir, nuestra fuente de datos.

Según las especificaciones del boceto, simplemente necesitamos información sobre el precio, el nombre y el recurso de la imagen que representará su exquisitez.

Comida.java

package com.herprogramacion.restaurantericoparico.modelo;

import com.herprogramacion.restaurantericoparico.R;

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

/**
 * Modelo de datos estático para alimentar la aplicación
 */
public class Comida {
    private float precio;
    private String nombre;
    private int idDrawable;

    public Comida(float precio, String nombre, int idDrawable) {
        this.precio = precio;
        this.nombre = nombre;
        this.idDrawable = idDrawable;
    }

    public static final List<Comida> COMIDAS_POPULARES = new ArrayList<Comida>();
    public static final List<Comida> BEBIDAS = new ArrayList<>();
    public static final List<Comida> POSTRES = new ArrayList<>();
    public static final List<Comida> PLATILLOS = new ArrayList<>();

    static {
        COMIDAS_POPULARES.add(new Comida(5, "Camarones Tismados", R.drawable.camarones));
        COMIDAS_POPULARES.add(new Comida(3.2f, "Rosca Herbárea", R.drawable.rosca));
        COMIDAS_POPULARES.add(new Comida(12f, "Sushi Extremo", R.drawable.sushi));
        COMIDAS_POPULARES.add(new Comida(9, "Sandwich Deli", R.drawable.sandwich));
        COMIDAS_POPULARES.add(new Comida(34f, "Lomo De Cerdo Austral", R.drawable.lomo_cerdo));
    }

    public float getPrecio() {
        return precio;
    }

    public String getNombre() {
        return nombre;
    }

    public int getIdDrawable() {
        return idDrawable;
    }
}

El miembro COMIDAS_POPULARES será el flujo de datos que tendremos para poblar el adaptador.

4. Con los datos ya preparados ahora podemos crear el layout de los ítems, así que añade un nuevo archivo llamado item_lista_inicio.xml.

Usaremos un FrameLayout para sobreponer el precio y el nombre sobre la imagen de cada elemento.

item_lista_inicio.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/miniatura_comida"
        android:layout_width="match_parent"
        android:layout_height="@dimen/altura_miniatura_comida"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/precio_comida"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left|bottom"
        android:layout_marginBottom="32dp"
        android:paddingLeft="@dimen/espacio_norma_1"
        android:text="Large Text"
        android:textColor="@android:color/white"
        android:textSize="48sp"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/nombre_comida"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left|bottom"
        android:paddingBottom="16dp"
        android:paddingLeft="16dp"
        android:text="Medium Text"
        android:textAppearance="@style/TextAppearance.AppCompat.Title"
        android:textColor="@android:color/white" />
</FrameLayout>

5. Crea una nueva clase llamada AdaptadorInicio.java para implementar el adaptador del recycler view para el inicio. Esta parte es muy fácil, solo no olvides alimentarlo con la lista COMIDAS_POPULARES.

AdaptadorInicio.Java

package com.herprogramacion.restaurantericoparico.ui;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.herprogramacion.restaurantericoparico.R;
import com.herprogramacion.restaurantericoparico.modelo.Comida;

/**
 * Adaptador para mostrar las comidas más pedidas en la sección "Inicio"
 */
public class AdaptadorInicio
        extends RecyclerView.Adapter<AdaptadorInicio.ViewHolder> {


    public static class ViewHolder extends RecyclerView.ViewHolder {
        // Campos respectivos de un item
        public TextView nombre;
        public TextView precio;
        public ImageView imagen;

        public ViewHolder(View v) {
            super(v);
            nombre = (TextView) v.findViewById(R.id.nombre_comida);
            precio = (TextView) v.findViewById(R.id.precio_comida);
            imagen = (ImageView) v.findViewById(R.id.miniatura_comida);
        }
    }

    public AdaptadorInicio() {
    }

    @Override
    public int getItemCount() {
        return Comida.COMIDAS_POPULARES.size();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_lista_inicio, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Comida item = Comida.COMIDAS_POPULARES.get(i);

        Glide.with(viewHolder.itemView.getContext())
                .load(item.getIdDrawable())
                .centerCrop()
                .into(viewHolder.imagen);
        viewHolder.nombre.setText(item.getNombre());
        viewHolder.precio.setText("$" + item.getPrecio());

    }


}

6. Con todos los componentes creados ya es posible poblar el recycler view desde el fragmento.

FragmentoInicio.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;

/**
 * Fragmento para la sección de "Inicio"
 */
public class FragmentoInicio extends Fragment {
    private RecyclerView reciclador;
    private LinearLayoutManager layoutManager;
    private AdaptadorInicio adaptador;

    public FragmentoInicio() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento_inicio, container, false);

        reciclador = (RecyclerView) view.findViewById(R.id.reciclador);
        layoutManager = new LinearLayoutManager(getActivity());
        reciclador.setLayoutManager(layoutManager);

        adaptador = new AdaptadorInicio();
        reciclador.setAdapter(adaptador);
        return view;
    }

}

7. Finalmente prepararemos el navigation drawer para seleccionar elementos y responder a los eventos creando el nuevo fragmento de inicio.

En primera instancia obtén la instancia del NavigationView en el método onCreate() de la actividad principal.

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);

Ahora comprueba en ese mismo lugar, si este está vacio. Si no es así, entonces prepara el navigation view y luego selecciona su ítem por defecto.

if (navigationView != null) {
    prepararDrawer(navigationView);
    // Seleccionar item por defecto
    seleccionarItem(navigationView.getMenu().getItem(0));
}

Para mí preparar el drawer significa setear la escucha de selección y configurar todos los atributos antes de iniciar con la selección. Para ello utilizo el método prepararDrawer().

private void prepararDrawer(NavigationView navigationView) {
    navigationView.setNavigationItemSelectedListener(
            new NavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(MenuItem menuItem) {
                    menuItem.setChecked(true);
                    seleccionarItem(menuItem);
                    drawerLayout.closeDrawers();
                    return true;
                }
            });

}

Recuerda onNavigationItemSelected nos provee un controlador para la selección. Dentro de este recibimos un objeto MenuItem para extraer toda la información del item seleccionado. Con setChecked() sombreamos el elemento seleccionado si usas true como parámetro.

La selección implica crear el contenido necesario de la sección, por lo que tenemos el método seleccionarItem() para ello.

Y como acción lógica una vez seleccionado cierra el drawer con closeDrawers() para seguir una secuencia limpia.

El método seleccionarItem() tiene un switch para determinar qué tipo de fragmento se creará una vez comparado el valor. Algo como esto:

private void seleccionarItem(MenuItem itemDrawer) {
    Fragment fragmentoGenerico = null;
    FragmentManager fragmentManager = getSupportFragmentManager();

    switch (itemDrawer.getItemId()) {
        case R.id.item_inicio:
            fragmentoGenerico = new FragmentoInicio();
            break;
        case R.id.item_cuenta:
            // Fragmento para la sección Cuenta
            break;
        case R.id.item_categorias:
            // Fragmento para la sección Categorías
            break;
        case R.id.item_configuracion:
            // Iniciar actividad de configuración
            break;
    }
    if (fragmentoGenerico != null) {
        fragmentManager
                .beginTransaction()
                .replace(R.id.contenedor_principal, fragmentoGenerico)
                .commit();
    }

    // Setear título actual
    setTitle(itemDrawer.getTitle());
}

Todo se define con el identificador del ítem que se obtiene a través de getItemId(). Este podemos compararlo con las constantes que tenemos en el archivo R.java.

Al final se reemplaza el contenido del RelativeLayout identificado por R.id.contenedor_principal que tenemos en actividad_principal.xml y luego se cambia el título de la actividad con el método getTitle().

Si corres el proyecto deberías ver la siguiente imagen:

Aplicación Android Con RecyclerView Restaurante

#5. Tabs Con Diferentes Fragmentos

Dentro de la sección Mi Cuenta es necesario usar tabs con fragmentos que tienen diferentes diseños. Por ejemplo, el diseño del perfil implementa dos cards para mostrar los datos de la cuenta.

Wireframe De Aplicación Android Para Un Perfil De Usuario

Sin embargo en las direcciones y tarjetas veremos distintas interfaces.

¿Cómo implementar este diseño en un TabLayout sabiendo que tiene distintos fragmentos?

De cierta manera, este asunto no tiene por qué afectar nuestro desarrollo, ya que el adaptador de fragmentos que usa a la hora de poblar un ViewPager puede recibir una lista de elementos genéricos de la clase Fragment. Lo que quiere decir que su método de inserción aceptará cualquier objeto que herede de esta clase.

El problema de noción está a la hora de incluir un ViewPager en el layout del fragmento. ¿Crees que es posible?

¡Claro que si!

En la documentación de Android se menciona que desde Android 4.2 es posible usar fragmentos anidados en tus aplicaciones, es decir, fragmentos dentro de otros fragmentos.

Fragmentos Anidados En Android 4.2

Por esta razón podemos incrustar el patrón Swipe Views dentro del layout de un fragmento con un soporte desde versiones 1.6.

Así que la idea de incorporar pestañas basadas en un fragmento es viable. En el caso de la sección mi cuenta necesitaremos:

  • Un Fragmento para las páginas de las pestañas y su layout correspondiente
  • Un fragmento para la sección PERFIL
  • Un fragmento para la sección DIRECCIONES
  • Un fragmento para la sección TARJETAS

También es posible crear un navigation drawer con diferentes actividades por sección para mantener el control de los layouts. Sin embargo ese será tema de un artículo futuro.

Veamos…

1. Añade un nuevo fragmento al proyecto y nómbralo FragmentoCuenta.java.

2. Abre su archivo de diseño y borrar el contenido por defecto. La idea es hacer de este fragmento el contenedor de las páginas que se coordinarán con las pestañas de la sección Mi Cuenta.

Como vimos en el artículo TabLayout: ¿Cómo Añadir Pestañas En Android?, si deseamos tener un efecto deslizante entre páginas de contenido debes añadir un ViewPager que ocupe el espacio total del fragmento.

fragmento_paginado.xml

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3. El enfoque que estamos usando de solamente fragmentos dificulta insertar pestañas de forma descriptiva a través del layout del fragmento actual, ya que la App Bar se encuentra en el layout de la actividad principal. El actual fragmento lo que hace es reemplazar un contenedor de segundo nivel.

Así que para añadir las pestañas debemos hacer uso del diseño programático. Esto quiere decir que crearemos una nueva instancia de un objeto TabLayout y luego lo incrustaremos en la App Bar que está un nivel más arriba de la jerarquía de views.

La ventaja es que el método onCreateView() del fragmento trae en sus parámetros el contenedor padre de la jerarquía de views. Con este podemos buscar la instancia fácilmente y luego añadir las pestañas a través del método addView().

import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;

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


/**
 * Fragmento de la sección "Mi Cuenta"
 */
public class FragmentoCuenta extends Fragment {

    private AppBarLayout appBar;
    private TabLayout pestanas;

    public FragmentoCuenta() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento_paginado, container, false);

        if (savedInstanceState == null) {
            insertarTabs(container);
        }

        return view;
    }

    private void insertarTabs(ViewGroup container) {
        View padre = (View) container.getParent();
        appBar = (AppBarLayout) padre.findViewById(R.id.appbar);
        pestanas = new TabLayout(getActivity());
        pestanas.setTabTextColors(Color.parseColor("#FFFFFF"), Color.parseColor("#FFFFFF"));
        appBar.addView(pestanas);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        appBar.removeView(pestanas);
    }
}

Como ves, el método insertarTabs() es el encargado de añadir un nuevo TabLayout en la App Bar. Este recibe como parámetro el contenedor del fragmento que en este caso es el layout de la actividad principal.

Luego se obtiene una instancia de la app bar, consiguiendo el padre del contenedor a través de getParent() (en  contenido_principal.xml sería el elemento identificado con R.id.contenedor_principal) que sería un LinearLayout.

Esto permitirá añadir el view sin ningún problema. Obviamente al añadirlo, también hay que quitarlo al momento en que el fragmento se destruya con removeView().

Al ejecutar tendrás algo como:

Ejemplo TabLayout En Aplicación Android Librería De Diseño

4. A continuación crearemos el fragmento para la página PERFIL. Simplemente añade una nueva clase llamada FragmentoPerfil.

FragmentoPerfil.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;

/**
 * Fragmento para la pestaña "PERFIL" De la sección "Mi Cuenta"
 */
public class FragmentoPerfil extends Fragment {

    public FragmentoPerfil() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragmento_perfil, container, false);
    }
}

Y luego diseña las tarjetas para los datos del usuario y la contraseña como se vió en el boceto al inicio.

fragmento_perfil.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#dee4ee"
    android:orientation="vertical"
    android:padding="@dimen/espacio_norma_1">

    <TextView
        android:id="@+id/titulo_informacion_usuario"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingBottom="8dp"
        android:text="@string/etiqueta_info_usuario"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="2dp"
        card_view:cardUseCompatPadding="true">

        <GridLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:columnCount="2"
            android:padding="@dimen/espacio_norma_1"
            android:rowCount="2">

            <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginBottom="32dp"
                android:layout_marginRight="@dimen/espacio_norma_2"
                android:src="@drawable/usuario" />

            <TextView
                android:id="@+id/texto_nombre"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginBottom="32dp"
                android:text="James Revelo"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <ImageView
                android:id="@+id/imageView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginRight="8dp"
                android:src="@drawable/email" />

            <TextView
                android:id="@+id/texto_email"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="james@mail.com"
                android:textAppearance="?android:attr/textAppearanceSmall" />
        </GridLayout>
    </android.support.v7.widget.CardView>

    <TextView
        android:id="@+id/titulo_contrasena"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingBottom="@dimen/espacio_norma_2"
        android:paddingTop="@dimen/espacio_norma_1"
        android:text="@string/etiqueta_contrasena"
        android:textAppearance="?android:attr/textAppearanceSmall" />

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="2dp"
        card_view:cardUseCompatPadding="true">

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="@dimen/espacio_norma_1">

            <ImageView
                android:id="@+id/icono_password"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:layout_gravity="center"
                android:layout_marginRight="8dp"
                android:src="@drawable/contrasena" />

            <TextView
                android:id="@+id/texto_password"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_gravity="center_vertical"
                android:layout_toRightOf="@+id/icono_password"
                android:text="@string/texto_cambiar_contrasena"
                android:textAppearance="?android:attr/textAppearanceSmall" />

            <ImageView
                android:id="@+id/icono_indicador_derecho"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:src="@drawable/indicador_derecho" />

        </RelativeLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

En el momento en que añadamos las pestañas este fragmento luciría de la siguiente forma:

Perfil En Aplicación Android Con Material Design

5. Similar al paso anterior, esta vez diseñaremos el fragmento para las direcciones basándonos en el boceto.

Wireframe Lista De Direcciones Aplicación Android
Debido a que es una lista, necesitamos crear un layout para el fragmento con un recycler view. Algo tan sencillo como:

fragmento_grupo_items.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/reciclador"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />

El layout de los ítems no es tan complicado. Solo son una serie de cuatro textos verticales con los datos de la dirección, el departamento, ciudad y teléfono.

Adicionalmente se añade un icono para decirle al usuario que cada ítem es editable.

item_lista_direcciones.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/espacio_norma_1">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/texto_direccion"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Dirección"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/texto_departamento"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Departamento"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/texto_ciudad"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Ciudad"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/texto_telefono"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Teléfono"
            android:textAppearance="?android:attr/textAppearanceSmall" />
    </LinearLayout>

    <ImageView
        android:id="@+id/icono_indicador_derecho"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:src="@drawable/indicador_derecho" />
</RelativeLayout>

Lo siguiente es crear el adaptador para las direcciones. Debido a que este fragmento es muy sencillo, podemos incluir la fuente de datos como clase interna.

AdaptadorDirecciones.java

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.herprogramacion.restaurantericoparico.R;

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

/**
 * Adaptador para poblar la lista de direcciones de la sección "Mi Cuenta"
 */
public class AdaptadorDirecciones
        extends RecyclerView.Adapter<AdaptadorDirecciones.ViewHolder> {


    public static class ViewHolder extends RecyclerView.ViewHolder {
        // Campos respectivos de un item
        public TextView direccion;
        public TextView departamento;
        public TextView ciudad;
        public TextView telefono;

        public ViewHolder(View v) {
            super(v);
            direccion = (TextView) v.findViewById(R.id.texto_direccion);
            departamento = (TextView) v.findViewById(R.id.texto_departamento);
            ciudad = (TextView) v.findViewById(R.id.texto_ciudad);
            telefono = (TextView) v.findViewById(R.id.texto_telefono);
        }
    }


    public AdaptadorDirecciones() {
    }

    @Override
    public int getItemCount() {
        return Direccion.DIRECCIONES.size();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_lista_direccion, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Direccion item = Direccion.DIRECCIONES.get(i);
        viewHolder.direccion.setText(item.numeroDireccion);
        viewHolder.departamento.setText(item.departamento);
        viewHolder.ciudad.setText(item.ciudad);
        viewHolder.telefono.setText(item.telefono);
    }

    /**
     * Modelo de datos para probar el adaptador
     */
    public static class Direccion {
        public String numeroDireccion;
        public String departamento;
        public String ciudad;
        public String telefono;

        public Direccion(String numeroDireccion, String departamento,
                         String ciudad, String telefono) {
            this.numeroDireccion = numeroDireccion;
            this.departamento = departamento;
            this.ciudad = ciudad;
            this.telefono = telefono;
        }

        public final static List<Direccion> DIRECCIONES = new ArrayList<Direccion>();

        static {
            DIRECCIONES.add(new Direccion("Cra 24 #2C-50", "Valle", "Cali", "3459821"));
            DIRECCIONES.add(new Direccion("Calle 100 Trans. 23", "Valle", "Cali", "4992600"));
            DIRECCIONES.add(new Direccion("Ave. 3ra N. #20-10", "Valle", "Cali", "4400725"));
        }
    }


}

Un detalle adicional. Los recycler views se pueden estilizar con la subclase RecyclerView.ItemDecoration. Esta permite recrear la forma en que son dibujados los elementos de la lista.

El boceto mostraba que usaríamos líneas divisorias para diferenciar los elementos, por lo que crearemos una decoración sencilla para este caso.

En primer lugar crea un nuevo drawable XML con un figura linear como se muestra en la siguiente definición.

linea_divisoria.xml

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

    <size
        android:width="1dp"
        android:height="1dp" />

    <solid android:color="@android:color/darker_gray" />

</shape>

Ahora crea una nueva clase que extienda de ItemDecoration y modifica su método onDrawOver() para renderizar el drawable desde el extremo izquierdo hacia el derecho:

DecoracionLineaDivisoria.java

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.herprogramacion.restaurantericoparico.R;

/**
 * ItemDecoration personalizado para dibujar la linea drawable/linea_divisoria.xml en los
 * elementos de un recycler view
 */
public class DecoracionLineaDivisoria extends RecyclerView.ItemDecoration {
    private Drawable lineaDivisoria;

    public DecoracionLineaDivisoria(Context context) {
        lineaDivisoria = ContextCompat.getDrawable(context, R.drawable.linea_divisoria);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + lineaDivisoria.getIntrinsicHeight();

            lineaDivisoria.setBounds(left, top, right, bottom);
            lineaDivisoria.draw(c);
        }
    }
}

Finalmente dentro de FragmentoDirecciones recupera el recycler view y añade un nuevo adaptador junto a la decoración.

FragmentoDirecciones.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;


/**
 * Fragmento para la pestaña "DIRECCIONES" De la sección "Mi Cuenta"
 */
public class FragmentoDirecciones extends Fragment {

    private LinearLayoutManager linearLayout;

    public FragmentoDirecciones() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento_grupo_items, container, false);

        RecyclerView reciclador = (RecyclerView)view.findViewById(R.id.reciclador);
        linearLayout = new LinearLayoutManager(getActivity());
        reciclador.setLayoutManager(linearLayout);

        AdaptadorDirecciones adaptador = new AdaptadorDirecciones();
        reciclador.setAdapter(adaptador);
        reciclador.addItemDecoration(new DecoracionLineaDivisoria(getActivity()));

        return view;
    }


}

Al momento de coordinar las pestañas con las páginas el resultado para este fragmento debería ser el siguiente:

Direcciones En Aplicación Android

6. Ahora es el turno del fragmento de la sección TARJETAS. Se supone que este contiene la lista de las tarjetas que ha usado el usuario para adquirir comidas a domicilio. Sin embargo en este caso asumiremos que no existe ninguna, por lo que el boceto mostrará un mensaje asociado a la situación.

WireFrame Aplicación Android Tarjetas De Crédito

Este diseño es el más simple. Solo añade un nuevo fragmento que infle el layout de un ImageView + un TextView (o un text view compuesto) y listo.

FragmentoTarjetas.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;

/**
 * Fragmento para la pestaña "TARJETAS" de la sección "Mi Cuenta"
 */
public class FragmentoTarjetas extends Fragment {

    public FragmentoTarjetas() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragmento_tarjetas, container, false);
    }


}

El diseño sería el siguiente:

fragmento_tarjetas.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imagen_no_tarjeta"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/tarjeta_credito" />

    <TextView
        android:id="@+id/texto_no_tarjeta"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="@string/texto_no_tarjetas"
        android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>

Este pequeño código produciría el siguiente aspecto del fragmento:

Tarjetas En Aplicación Android

7. Finalmente abre FragmentoCuenta.java y obtén una instancia y:

  • Obtén una instancia del ViewPager del fragmento.
  • Crea un FragmentStatePagerAdapter para poblar el pager.
  • Añade una instancia de cada fragmento creado anteriormente.
  • Usa el método setupWithViewPager() para coordinar las pestañas y páginas.

FragmentoCuenta.java

import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;

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


/**
 * Fragmento de la sección "Mi Cuenta"
 */
public class FragmentoCuenta extends Fragment {

    private AppBarLayout appBar;
    private TabLayout pestanas;
    private ViewPager viewPager;

    public FragmentoCuenta() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento_paginado, container, false);

        if (savedInstanceState == null) {
            insertarTabs(container);

            // Setear adaptador al viewpager.
            viewPager = (ViewPager) view.findViewById(R.id.view_pager_mi_cuenta);
            poblarViewPager(viewPager);
            pestanas.setupWithViewPager(viewPager);
        }

        return view;
    }

    private void insertarTabs(ViewGroup container) {
        View padre = (View) container.getParent();
        appBar = (AppBarLayout) padre.findViewById(R.id.appbar);
        pestanas = new TabLayout(getActivity());
        pestanas.setTabTextColors(Color.parseColor("#FFFFFF"), Color.parseColor("#FFFFFF"));
        appBar.addView(pestanas);
    }

    private void poblarViewPager(ViewPager viewPager) {
        AdaptadorSecciones adapter = new AdaptadorSecciones(getFragmentManager());
        adapter.addFragment(new FragmentoPerfil(), getString(R.string.titulo_tab_perfil));
        adapter.addFragment(new FragmentoDirecciones(), getString(R.string.titulo_tab_direcciones));
        adapter.addFragment(new FragmentoTarjetas(), getString(R.string.titulo_tab_tarjetas));
        viewPager.setAdapter(adapter);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        appBar.removeView(pestanas);
    }

    /**
     * Un {@link FragmentStatePagerAdapter} que gestiona las secciones, fragmentos y
     * títulos de las pestañas
     */
    public class AdaptadorSecciones extends FragmentStatePagerAdapter {
        private final List<Fragment> fragmentos = new ArrayList<>();
        private final List<String> titulosFragmentos = new ArrayList<>();

        public AdaptadorSecciones(FragmentManager fm) {
            super(fm);
        }

        @Override
        public android.support.v4.app.Fragment getItem(int position) {
            return fragmentos.get(position);
        }

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

        public void addFragment(android.support.v4.app.Fragment fragment, String title) {
            fragmentos.add(fragment);
            titulosFragmentos.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return titulosFragmentos.get(position);
        }
    }
}

Recuerda que si el contenido de los fragmentos asociados a las pestañas varía de continuamente es mejor usar la clase FragmentStatePagerAdapter que FragmentPagerAdapter.

El primero recicla las vistas cada vez que el ciclo de vida del fragmento acaba, lo que facilitará el traspaso entre las opciones del navigation drawer sin alterar el contenido.

Para finalizar esta sección ejecuta el proyecto desarrollado hasta el momento y comprueba el funcionamiento de la sección Mi cuenta.

#6. Tabs Con Grids En Fragmentos Similares

La sección Categorías es similar a Mi Cuenta, ya que tenemos tabs asociadas a un fragmento. Solo que esta vez el contenido se define por grids de comidas segmentadas en categorías.

Wireframe Aplicación Android Con Tabs y Grids

Al contener las pestañas elementos uniformes, el desarrollo se nos facilita mucho, ya que solo necesitamos un adaptador que se alimente de una fuente de datos personalizada, pero con la misma estructura de información.

Para llevar a cabo esta implementación requeriremos:

  • Un fragmento para la sección Categorías.
  • Un fragmento genérico que represente el contenido de todas las categorías.
  • Un layout para el diseño de los ítems pertenecientes a los grids.
  • Un adaptador para los ítems en los grids.

Pasemos a la acción…

1. Crea un nuevo fragmento llamado FragmentoCategorias.java e infla su contenido desde el layout existente fragmento_paginado.xml.

2. Copia y pega exactamente el mismo código del FragmentoCuenta.java en su interior excepto el cuerpo del método poblarViewPager(). Recuerda que usaremos fragmentos distintos para la creación de los grids por cada sección.

3. Por segunda vez añade un fragmento nuevo y nómbralo FragmentoCategoria.java. Debido a que usaremos un recycler view para generar las grillas, podemos reutilizar el layout fragmento_grupo_items.xml para inflar este fragmento.

4. Añade a la clase Comida.java tres nuevas listas para representar los ítems proyectados en las grillas. Sus nombres serán PLATILLOS, BEBIDAS y POSTRES como en los títulos de las pestañas.

Dentro de Comida.java

public static final List<Comida> BEBIDAS = new ArrayList<>();
public static final List<Comida> POSTRES = new ArrayList<>();
public static final List<Comida> PLATILLOS = new ArrayList<>();

static {
    ...

    PLATILLOS.add(new Comida(5, "Camarones Tismados", R.drawable.camarones));
    PLATILLOS.add(new Comida(3.2f, "Rosca Herbárea", R.drawable.rosca));
    PLATILLOS.add(new Comida(12f, "Sushi Extremo", R.drawable.sushi));
    PLATILLOS.add(new Comida(9, "Sandwich Deli", R.drawable.sandwich));
    PLATILLOS.add(new Comida(34f, "Lomo De Cerdo Austral", R.drawable.lomo_cerdo));

    BEBIDAS.add(new Comida(3, "Taza de Café", R.drawable.cafe));
    BEBIDAS.add(new Comida(12, "Coctel Tronchatoro", R.drawable.coctel));
    BEBIDAS.add(new Comida(5, "Jugo Natural", R.drawable.jugo_natural));
    BEBIDAS.add(new Comida(24, "Coctel Jordano", R.drawable.coctel_jordano));
    BEBIDAS.add(new Comida(30, "Botella Vino Tinto Darius", R.drawable.vino_tinto));

    POSTRES.add(new Comida(2, "Postre De Vainilla", R.drawable.postre_vainilla));
    POSTRES.add(new Comida(3, "Flan Celestial", R.drawable.flan_celestial));
    POSTRES.add(new Comida(2.5f, "Cupcake Festival", R.drawable.cupcakes_festival));
    POSTRES.add(new Comida(4, "Pastel De Fresa", R.drawable.pastel_fresa));
    POSTRES.add(new Comida(5, "Muffin Amoroso", R.drawable.muffin_amoroso));
}

5. Lo siguiente es crear un diseño para los ítems del grid. En este caso usaremos la modalidad footer con doble línea como se muestra en la documentación y en el boceto.

Formato Two Line Grid List En Material Design

El layout se compone de la imagen superior de cada comida con una altura predeterminada a 192dp. El footer será un LinearLayout con dos Text Views, donde la primer línea será el precio y la segunda el nombre de la comida.

item_lista_categorias.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="1dp">

    <ImageView
        android:id="@+id/miniatura_comida"
        android:layout_width="match_parent"
        android:layout_height="192dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/accentColor"
        android:orientation="vertical"
        android:padding="@dimen/espacio_norma_1">

        <TextView
            android:id="@+id/precio_comida"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Precio"
            android:textAppearance="@style/TextAppearance.AppCompat.Subhead.Inverse"
            android:textStyle="normal|bold" />

        <TextView
            android:id="@+id/nombre_comida"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nombre"
            android:textAppearance="@style/TextAppearance.AppCompat.Subhead.Inverse"
            android:textSize="12sp" />

    </LinearLayout>
</LinearLayout>

Más adelante este diseño produciría el siguiente aspecto visual:

Item Grid List Aplicación Android Restaurante
6. Crea un adaptador para los elementos que permita recibir como parámetro una lista de ítems genéricos. Esto con el fin de crear las tres variaciones de las categorías.

AdaptadorCategorias.java

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.herprogramacion.restaurantericoparico.R;
import com.herprogramacion.restaurantericoparico.modelo.Comida;

import java.util.List;

/**
 * Adaptador para comidas usadas en la sección "Categorías"
 */
public class AdaptadorCategorias
        extends RecyclerView.Adapter<AdaptadorCategorias.ViewHolder> {


    private final List<Comida> items;

    public static class ViewHolder extends RecyclerView.ViewHolder {
        // Campos respectivos de un item
        public TextView nombre;
        public TextView precio;
        public ImageView imagen;

        public ViewHolder(View v) {
            super(v);

            nombre = (TextView) v.findViewById(R.id.nombre_comida);
            precio = (TextView) v.findViewById(R.id.precio_comida);
            imagen = (ImageView) v.findViewById(R.id.miniatura_comida);
        }
    }


    public AdaptadorCategorias(List<Comida> items) {
        this.items = items;
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.item_lista_categorias, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        Comida item = items.get(i);

        Glide.with(viewHolder.itemView.getContext())
                .load(item.getIdDrawable())
                .centerCrop()
                .into(viewHolder.imagen);
        viewHolder.nombre.setText(item.getNombre());
        viewHolder.precio.setText("$" + item.getPrecio());

    }


}

7. Abre de nuevo FragmentoCategoria.java y añade el siguiente código.

FragmentoCategoria.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.herprogramacion.restaurantericoparico.R;
import com.herprogramacion.restaurantericoparico.modelo.Comida;

/**
 * Fragmento que representa el contenido de cada pestaña dentro de la sección "Categorías"
 */
public class FragmentoCategoria extends Fragment {

    private static final String INDICE_SECCION
            = "com.restaurantericoparico.FragmentoCategoriasTab.extra.INDICE_SECCION";

    private RecyclerView reciclador;
    private GridLayoutManager layoutManager;
    private AdaptadorCategorias adaptador;

    public static FragmentoCategoria nuevaInstancia(int indiceSeccion) {
        FragmentoCategoria fragment = new FragmentoCategoria();
        Bundle args = new Bundle();
        args.putInt(INDICE_SECCION, indiceSeccion);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragmento_grupo_items, container, false);

        reciclador = (RecyclerView) view.findViewById(R.id.reciclador);
        layoutManager = new GridLayoutManager(getActivity(), 2);
        reciclador.setLayoutManager(layoutManager);

        int indiceSeccion = getArguments().getInt(INDICE_SECCION);

        switch (indiceSeccion) {
            case 0:
                adaptador = new AdaptadorCategorias(Comida.PLATILLOS);
                break;
            case 1:
                adaptador = new AdaptadorCategorias(Comida.BEBIDAS);
                break;
            case 2:
                adaptador = new AdaptadorCategorias(Comida.POSTRES);
                break;
        }

        reciclador.setAdapter(adaptador);

        return view;
    }

}

Las piezas de código tienen como fin la personalización del recycler view dependiendo de la categoría.

Al principio encontrarás la clave de un extra que representa el índice de la pestaña para la cual se creará el fragmento.

El método de clase nuevaInstancia() permite crear una nueva instancia del fragmento basado en el índice de la sección como argumento.

Dicho argumento es obtenido en el método onCreateView() para determinar con un switch que fuente de datos irá en el constructor del adaptador. Luego de la decisión, el adaptador es asignado al recycler view que se creó.

Recuerda que si deseas crear un Grid List con el RecyclerView es necesario usar un GridLayoutManager en la inicialización. El constructor de este elemento recibe el contexto y la cantidad de columnas que habrá (en este caso 2).

8. Finalmente puedes modificar el método poblarViewPager() de FragmentoCategorias añadiendo tres instancias con índices del 0 al 2 para satisfacer la estructura de las pestañas.

Dentro de FragmentoCategorias.java

private void poblarViewPager(ViewPager viewPager) {
    AdaptadorSecciones adapter = new AdaptadorSecciones(getFragmentManager());
    adapter.addFragment(FragmentoCategoria.nuevaInstancia(0), getString(R.string.titulo_tab_platillos));
    adapter.addFragment(FragmentoCategoria.nuevaInstancia(1), getString(R.string.titulo_tab_bebidas));
    adapter.addFragment(FragmentoCategoria.nuevaInstancia(2), getString(R.string.titulo_tab_postres));
    viewPager.setAdapter(adapter);
}

Si deseas añadir un action button de búsqueda dentro de la Toolbar, entonces crea el siguiente recurso de menú.

menu_categorias.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".ActividadPrincipal">
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        app:showAsAction="never" />
    <item
        android:id="@+id/action_search"
        android:icon="@drawable/busqueda"
        android:orderInCategory="1"
        android:title="@string/action_search"
        app:showAsAction="ifRoom" />
</menu>

Y ahora habilita la contribución del fragmento a la action bar con el método setHasOptionsMenu() dentro de onCreate() y luego infla el recurso dentro de onCreateOptionsMenu().

Dentro de FragmentoCategorias.java

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_categorias, menu);
}

Si ejecutas la aplicación tendrás el siguiente resultado:

Ejemplo Aplicación Android Con Menú De Comidas

#7. Iniciar Actividad Desde Navigation Drawer

Ya para finalizar nuestro experimento veremos cómo iniciar una actividad de ajustes desde el navigation drawer. Según el boceto Rico Pa’ Rico tiene una sola preferencia relacionada con la configuración de la frecuencia de notificaciones por correo. Esta a su vez se encuentra dentro de la categoría “Notificaciones”.

Wireframe De Actividad De Configuración En Android

A simple vista se reconoce que esta preferencia es del tipo ListPreference como vimos en el artículo ¿Cómo Crear Una Actividad De Preferencias En Android?. Donde se selecciona una de las opciones mostradas en un dialogo para tomar una decisión dentro de la aplicación.

La creación de esta actividad solamente requiere:

  • Una actividad con Toolbar junto a su respectivo layout.
  • Un fragmento de preferencias.
  • Un archivo strings.xml para preferencias.
  • Un recurso xml para mapear las preferencias que se inflarán en el fragmento.

Continuemos…

1. Crea una nueva actividad llamada ActividadConfiguracion.java junto a un layout que contenga una Toolbar y un contenido central.

actividad_configuracion.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <FrameLayout
        android:id="@+id/contenedor_configuracion"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

2. Dentro de la actividad añade un fragmento como miembro y extiéndelo de la clase PreferenceFragment. Solo necesitamos que en su método onCreate() se inflen las preferencias a través de addPreferencesFromResource().

ActividadConfiguracion.java

import android.app.FragmentTransaction;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

import com.herprogramacion.restaurantericoparico.R;

/**
 * Actividad para la configuración de preferencias
 */

public class ActividadConfiguracion extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.actividad_configuracion);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.contenedor_configuracion, new FragmentoConfiguracion());
        ft.commit();

        agregarToolbar();
    }

    private void agregarToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        final ActionBar ab = getSupportActionBar();
        if (ab != null) {
            ab.setDisplayHomeAsUpEnabled(true);
        }
    }

    public static class FragmentoConfiguracion extends PreferenceFragment {

        public FragmentoConfiguracion() {
            // Constructor Por Defecto
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferencias);
        }
    }
}

3. Ve a res/values y crea una nuevo recursos de strings con el nombre de strings_actividad_configuracion.xml y añade los textos necesarios que se ven en el boceto para proyectar la preferencia.

strings_actividad_configuracion.xml

<resources>
    <string name="titulo_actividad_configuracion">Configuración</string>

    <string name="categoria_notificaciones">Notificaciones</string>

    <string name="titulo_preferencia">Frecuencia de notificaciones por correo</string>
    <string name="key_preferencia">lista_frecuencias</string>
    <string-array name="lista_frecuencia">
        <item>Un correo diario</item>
        <item>Un correo a la semana</item>
        <item>Un correo al mes</item>
        <item>No quiero recibir correos</item>
    </string-array>
    <string-array name="lista_valores_frecuencia">
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </string-array>

</resources>

El recurso anterior contiene el nombre de la actividad de preferencias, el nombre de la categoría. También el título de la preferencia de lista, su clave (key) y dos arrays para representar el texto de las opciones y sus valores correspondientes.

4. Crea un nuevo recurso dentro de la carpeta xml (si no existe, créala) con un nodo PreferenceScreen. Luego añade una categoría junto a la ListPreference que ya veníamos planeando.

preferencias.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory
        android:key="categoria_notificaciones"
        android:title="@string/categoria_notificaciones">
        <ListPreference
            android:defaultValue="0"
            android:entries="@array/lista_frecuencia"
            android:entryValues="@array/lista_valores_frecuencia"
            android:key="@string/key_preferencia"
            android:negativeButtonText="@null"
            android:positiveButtonText="@null"
            android:summary="%s"
            android:title="@string/titulo_preferencia" />
    </PreferenceCategory>
</PreferenceScreen>

5. Modifica el estilo de la actividad principal en el Android Manifest a @style/Theme.ConNavigationDrawer. Esto evitará que la status bar se vea translucida debido al efecto que se usa en la actividad principal para seguir las especificaciones del navigation drawer.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.herprogramacion.restaurantericoparico" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.RicoPaRico" >
        <activity
            android:name=".ui.ActividadPrincipal"
            android:label="@string/app_name"
            android:theme="@style/Theme.ConNavigationDrawer">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ui.ActividadConfiguracion"
            android:label="@string/titulo_actividad_configuracion"
            android:parentActivityName=".ui.ActividadPrincipal" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.ActividadPrincipal" />
        </activity>
    </application>

</manifest>

6. Dentro de ActividadPrincipal.java usa el  método startActivity() para iniciar nuestra actividad de configuración. Recuerda que esto va sobre el método seleccionarItem() y el identificador de la sección de configuración es R.id.item_configuracion.

Dentro de ActividadPrincipal.java

private void seleccionarItem(MenuItem itemDrawer) {
    Fragment fragmentoGenerico = null;
    FragmentManager fragmentManager = getSupportFragmentManager();

    switch (itemDrawer.getItemId()) {
        case R.id.item_inicio:
            fragmentoGenerico = new FragmentoInicio();
            break;
        case R.id.item_cuenta:
            fragmentoGenerico = new FragmentoCuenta();
            break;
        case R.id.item_categorias:
            fragmentoGenerico = new FragmentoCategorias();
            break;
        case R.id.item_configuracion:
            startActivity(new Intent(this, ActividadConfiguracion.class));
            break;
    }
    if (fragmentoGenerico != null) {
        fragmentManager
                .beginTransaction()
                .replace(R.id.contenedor_principal, fragmentoGenerico)
                .commit();
    }

    // Setear título actual
    setTitle(itemDrawer.getTitle());
}

Si todo salió bien, cuando ejecutes la aplicación y selecciones la sección de configuración, se iniciará nuestra actividad y podremos variar el valor de la preferencia de notificaciones.

Iniciar Una Actividad Desde Un Navigation Drawer

Conclusión

El patrón recomendado por Google para usar dos niveles de navegación es el de Navigation Drawer y Tabs.

Este componente brinda flexibilidad y organización a la hora de crear secciones que ayuden al usuario a tener una visión global de la aplicación.

Vimos cómo usar varios tipos de layouts para generar un segundo nivel de navegación,basados en elemento como listas, grid views y pestañas.

La aplicación Rico Pa’ Rico permitió usar diferentes fragmentos para las secciones  del navigation drawer. Esta vez nuestro desarrollo fue dinámico gracias a los fragmentos anidados.

Como se mencionó arriba, también es posible crear una navigation drawer con diferentes actividades. Pero este es un tema que será tratado individualmente.

Por ahora puedes ir pensando en alimentar esta plantilla con datos reales a través de un web service y sincronizar los datos locales con tu servidor.