Google I/O 2015 nos trajo consigo una serie de herramientas para facilitar la vida a los desarrolladores y en esta oportunidad dedicaremos una seríe de artículos sobre Design Support Library que nos ayudara a la hora de emplear Material Design en nuestras apps.

  1. 1. Navigation View
  2. 2. Floating Labels
  3. 3. Floating Action Buttons
  4. 4. Snackbar
  5. 5. Tab Layout
  6. 6. Coordinator Layout
  7. 7. Collapsing Toolbar
  8. 8. Animations

Navigation View

En este primer articulo aprenderemos sobre el Navigation View. Cuando Material Design fue lanzado nos proporcionaron un estandar de como debe verse y sentirse (Look & Feel) un Navigation Drawer, cuya implementación de estas directrices llevaban mucho tiempo, pero con la llegada del Navigation View las cosas se hicieron super fáciles.

¿Qué lo hace diferente?

Anteriormente para implementar una navegación lateral se usaba regularmente un ListView el cual personalizabamos y configurabamos una serie de parametros para obtener un resultado final optimo. Ahora implementando un Navigation View contamos con un parametro opcional donde proporcionamos un Layout para nuestro Header y un menu.xml el cual sirve para porporcionar las opciones de navegacion. Luego de eso solo tenemos que declarar un Listener para capturar y ejecutar una accion, cuando una de las opciones es seleccionada.

Requerimientos

  1. Android Studio
  2. AppCompat-v7 Support Library
  3. Design Support Library
  4. Circle Image Library // Esta dependencia es opcional y sirve para mostrar imagenes circulares

Implementación

Paso 1: Creamos un nuevo proyecto en android studio.

Al crear el nuevo proyecto elegimos de nombre en este caso My Material App y elegimos como template un empty activity que es lo que usaremos para este ejemplo. Tambié modificamos un poco nuestro style.xml para no tener problemas cuando usemos un Toolbar entonces agregamos lo siguiente dentro de nuestro AppTheme.

<!--Desactivamos el ActionBar-->
<item name="windowActionBar">false</item>
<!--hacemos que el toolbar se sobreponga al contenido-->
<item name="windowActionModeOverlay">true</item>

<!--Permitimos editar el color de fondo del systemBar-->
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<!--Hacemos el status bar transparente-->
<item name="android:statusBarColor">@android:color/transparent</item>

Paso 2: Agregamos las dependencias que usaremos en nuestro proyecto.

Para añadir las dependencias mencionadas en la parte de Requerimientos agregamos lo siguiente en la parte de dependencies en build.gradle

dependencies {
    ... //Autogenerado por android studio 
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.android.support:design:22.2.0'
    compile 'de.hdodenhof:circleimageview:2.0.0' // Opcional
}

Paso 3: Creamos el menu que vamos a utilizar en el Navigation View.

Antes que nada como hemos seleccionado como template inicial al crear nuestro proyecto un empty activity es probable que no se nos ha creado la carpeta menu dentro de res por lo tanto para crearla debemos dar click derecho en res y luego seleccionar New -> Android resource directory y en la ventana que se abre debemos poner el nombre menu y en Resource type (Tipo de Recurso) elegir menu

Luego para crear nuestro menu (navigation_main.xml) damos click derecho en la carpeta res -> menu y en el desplegable que se abre seleccionamos New -> Menu resource file y le damos el nombre de navigation_main.

Dentro del archivo creado navigation_main.xml debemos poner lo siguiente:

<?xml version="1.0" econding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <!--<item
            android:id="@+id/calendario" // id con el cual identificamos el item cuando es seleccionado
            android:icon="@drawable/ic_menu_calendar" // icono que representa al item
            android:title="Calendario"/> // titulo del item -->

        <item
            android:id="@+id/calendario"
            android:icon="@drawable/ic_menu_calendar"
            android:title="Calendario"/>

        <item
            android:id="@+id/camara"
            android:icon="@drawable/ic_menu_camera"
            android:title="Camara"/>

        <item
            android:id="@+id/ajustes"
            android:icon="@drawable/ic_menu_settings"
            android:title="Ajustes"/>
    </group>
</menu>

Los iconos puedes encontrarlos en el siguiente link: Material Design Icons

Paso 4: Creamos el layout para el header de nuestro Navigation View.

Dentro de la carpeta layout creamos nuestro archivo navigation_header_main.xml el cual tendrá dentro de un RelativeLayout una CircleImageView (Imagen circular usando la libraría Circle Image Library) y dos TextView uno para el nombre del usuario y el segundo para el correo. Nuestro archivo quedaría de la siguiente manera:

<?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="192dp"
    android:background="@drawable/navigation_header_bg"
    android:padding="@dimen/activity_horizontal_margin"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <!--Es un ImageView que nos generará una imagen circular-->
    <de.hdodenhof.circleimageview.CircleImageView
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_above="@+id/text_username"
        android:layout_marginBottom="16dp"
        android:scaleType="centerCrop"
        android:src="@drawable/user_profile"/>

    <TextView
        android:id="@+id/text_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/text_email"
        android:text="Juan Carlos"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/text_email"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="juan.carlos@gmail.com"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
</RelativeLayout>

Paso 5: Modificamos el layout de nuestro Activity para mostrar contenido y nuestro Navigation View.

Antes que nada crearemos un layout aparte (toolbar.xml) para nuestro Toolbar que luego incluiremos en nuestro activity_main.xml usando include.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    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="@dimen/abc_action_bar_default_height_material"
    android:background="@color/colorPrimary"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

Ahora modificamos nuestro activity_main.xml e implementamos nuestro Toolbar y NavigationView

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">


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

        <include
            android:id="@+id/toolbar"
            layout="@layout/toolbar"/>

        <FrameLayout
            android:id="@+id/frame_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <!--android:layout_gravity="start" // Declaramos el NavigationView estará a la izquierda
        app:itemBackground="@android:color/transparent" // Esto hace que el item no tenga backgroun cuando este o no seleccionado
        app:headerLayout="@layout/navigation_header_main" // Declaramos el layout para nuestro header, este parametro es opcional
        app:menu="@menu/navigation_main"/> // Declaramos el menu que usaremos para nuestro NavigationView, este parametro es requerido-->

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@android:color/white"
        app:itemBackground="@android:color/transparent" 
        app:headerLayout="@layout/navigation_header_main"
        app:menu="@menu/navigation_main"/>
</android.support.v4.widget.DrawerLayout>

Paso 6: Creamos nuestra clase ContentFragment e implementamos nuestra clase ActivityMain.

Para hacer que nuestro Navigation View funcione debemos agregar la funcionalidad en nuestro ActivityMain y debido a que utilizaremos un Fragment para mostrar contenido de acuerdo a la opción seleccionada primero crearemos nuestra clase ContentFragment y su respectivo Layout de manera rapida

ContentFragment.java

package com.bytpher.example.mymaterialapp;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class ContentFragment extends Fragment {

    /**
     * Este argumento del fragmento representa el título de cada
     * sección.
     */
    public static final String ARG_SECTION_TITLE = "section_title";

    public static ContentFragment newInstance(String sectionTitle) {
        ContentFragment fragment = new ContentFragment();

        // Establecemos el titulo enviado como argumento del fragment
        Bundle args = new Bundle();
        args.putString(ARG_SECTION_TITLE, sectionTitle);
        fragment.setArguments(args);
        return fragment;
    }


    public ContentFragment() {
        // Required empty public constructor
    }


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

        // Mostramos el titulo que guardamos como argumento del fragment de la sección en el TextView
        String title = getArguments().getString(ARG_SECTION_TITLE);
        TextView textView = (TextView) view.findViewById(R.id.text_view);
        textView.setText(title);
        return view;
    }


}

content_main.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="@dimen/activity_horizontal_margin">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>
</LinearLayout>

Ahora que ya contamos con nuestro Fragment procedemos con nuestro MainActivity.java

package com.bytpher.example.mymaterialapp;

import android.app.Fragment;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener { // Implementamos el Listener del NavigationView para ejecutar una acción cuando un item es seleccionado

    private NavigationView navigationView;
    private DrawerLayout drawerLayout;
    private Toolbar toolbar;

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

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        navigationView = (NavigationView) findViewById(R.id.navigation_view);
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

        // Establecemos el Toolbar como el actionbar
        setSupportActionBar(toolbar);

        // Inicializamos un ActionBarToggle que es el icono del menu con el cual podremos abrir nuestro NavigationView
        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_drawer, R.string.close_drawer);

        // Establecemos el actionbarToggle al drawer layout
        drawerLayout.setDrawerListener(actionBarDrawerToggle);

        // Llamamos a la funcion syncState para que se muestre nuestro icono del menu.
        actionBarDrawerToggle.syncState();

        // Establecemos un Listener para ejecutar una acción cuando un item es selccionado
        // como lo implementamos a nuestra activity pasamos como parametro nuestra clase MainActivity|this
        navigationView.setNavigationItemSelectedListener(this);

        if (savedInstanceState == null) {
            displayFragment(getResources().getString(R.string.app_name));
        }

    }

    // Cuando se presione el boton para regresar y el Navigation View esta abierto lo cerramos
    @Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
            drawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }


    @Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {
        menuItem.setChecked(true);

        // Obtenemos el titulo del item seleccionado
        String title = menuItem.getTitle()
                               .toString();

        // Actualizamos el fragment con el titulo del item
        displayFragment(title);

        return true;
    }

    private void displayFragment(String title) {

        // Enviamos el título como arguemento de la nueva instancia del fragment
        Fragment fragment = ContentFragment.newInstance(title);
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager
                .beginTransaction()
                .replace(R.id.frame_layout, fragment)
                .commit();

        drawerLayout.closeDrawers(); // Cerramos el NavigationView

        setTitle(title); // Cambiamos el título

    }
}

Listo, ya tenemos implementado nuestro Navigation View y en este caso hemos usado un Fragment para mostrar el nombre del item que seleccionemos esto se asemeja mucho a casos reales, ya que mostramos un contenido de acuerdo a la opcion que seleccionemos. Este es el resultado final de la App construida en este articulo.

Image title

Image title

Los recursos utilizados para este ejemplo los pueden encontrar aca.

Cualquier duda o recomendación puedes hacerla en los comentarios.