En este video te explicamos en detalle todo el proceso para publicar una Aplicación Android…
Proyecto: implementación de Navigation View en App Android
3.
Proyecto: implementación de Navigation View en App Android
Vamos a desarrollar un proyecto que nos servirá para mostrar paso a paso la implementación de un componente NavigationView
, utilizado para el diseño de un menú de navegación lateral, en una App Android.
Nos servirá de ejemplo práctico para ver los aspectos tratados en esta serie de tutoriales sobre Navigation Drawer y Navigation View, que recordamos se introdujo con la nueva librería de diseño Material Design, liberada junto con la versión de Android 5.0 Lollipop.
Descripción del proyecto Navigation View
Esta aplicación desplegará un menú lateral como el que vemos en imagen, y al pinchar, mostrará al usuario la opción de menú seleccionada en dicho panel (en la siguiente publicación mostraremos en detalle esta App ejemplo en un video):
Se comenzará en primer lugar por enumerar los elementos necesarios para el desarrollo del proyecto denominado «NavigationView»:
- Clase
SplashScreen
, que herede de la clase baseActivity
, encargada de lanzar una pantalla de presentación al iniciar la aplicación, proporcionando una mayor inmersión del usuario en la aplicación. - Clase
MainActivity
, que herede de la clase baseAppCompatActivity
, y que definirá la lógica de construcción y selección del componenteNavigationView
. - Clase
FragmentSeleccion
, que herede de la clase baseFragment
, encargada de mostrar información sobre el elemento del menú seleccionado. - Layout
activity_splash_screen.xml
, formado por una componente de tipoImageView
, que mostrará el logotipo de la aplicación. - Layout
activity_main.xml
, formado por un contenedorDrawerLayout
, que permite interactuar con la vista drawer, dentro del cual se encontrarán tanto unFrameLayout
, como el menú de navegaciónNavigationView
. - Layout
fragment_listado.xml
, formado por un controlTextView
para mostrar el elemento del menú seleccionado por el usuario. - Layout
cabecera.xml
, donde se define la parte superior delNavigationView
, en este caso formado por una imagen circular, y dos controlesTextView
, que muestran información sobre el usuario. - Layout
barrasuperior.xml
, que construye la barra de acción que se mostrará al iniciar la aplicación. Dicho layout estará formado por un controlToolBar
.
Estructura del proyecto
Documentación código fuente
Vamos a detallar las clases y ficheros de layout de este proyecto. Como siempre, podrás descargar todo el código al final de este tutorial (usuarios Premium)
NavigationView\app\src\main\java\com\academiaandroid\navigationview\MainActivity.java
Clase MainActivity
, que hereda de la clase base AppCompatActivity
, cuya principal tarea será la de establecer la lógica de construcción y selección del componente NavigationView, además de establecer la librería de soporte para implementar la barra de herramientas:
1 2 |
public class MainActivity extends AppCompatActivity{ |
Se define las diferentes variables para la construcción del NavigationView
y DrawerLayout
entre otros:
1 2 3 4 5 6 7 8 9 10 11 12 |
private Toolbar toolbar; private NavigationView navigationView; private DrawerLayout drawerLayout; private FragmentSeleccion fragment; private FragmentTransaction fragmentTransaction; private Bundle parametro; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); |
Se asigna a la variable de tipo Toolbar
, su control a nivel de layout:
1 2 |
toolbar = (Toolbar) findViewById(R.id.toolbar); |
Se establece en la Activity el ActionBar
:
1 |
setSupportActionBar(toolbar); |
Se asigna a la variable de tipo NavigationView
, su control a nivel de layout:
1 |
navigationView = (NavigationView) findViewById(R.id.navigation_view); |
Se establece la lógica encargada de controlar la pulsación de un elemento en el menú de navegación:
1 2 3 |
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { |
En las siguientes líneas se implementa el método que será lanzado cuando se pulse un elemento del menú de navegación:
1 2 3 4 5 6 |
@Override public boolean onNavigationItemSelected(MenuItem menuItem) { if (menuItem.isChecked()) menuItem.setChecked(false); else menuItem.setChecked(true); |
Cierre del drawer al seleccionar un elemento del menú:
1 2 3 4 5 6 |
drawerLayout.closeDrawers(); fragment = new FragmentSeleccion(); parametro = new Bundle(); fragmentTransaction = getSupportFragmentManager().beginTransaction(); |
Aquí se comprobará que ítem ha sido seleccionado, para mostrar información referente a dicha selección:
1 2 3 |
switch (menuItem.getItemId()) { |
Al seleccionar cualquiera de los elementos del menú de navegación, se mostrará el fragment definido con un texto indicando información de la selección:
1 2 3 4 5 6 |
case R.id.ajustes: parametro.putString("ajustes", "Ha seleccionado la opción: " + getResources().getString(R.string.ajustes)); fragment.setArguments(parametro); fragmentTransaction = getSupportFragmentManager().beginTransaction(); |
Se sustituye el FrameLayout
definido en la Activity
por el fragment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
fragmentTransaction.replace(R.id.frame, fragment);; fragmentTransaction.commit(); return true; case R.id.calendario: parametro.putString("calendario", "Ha seleccionado la opción: " + getResources().getString(R.string.calendario) + " --> " + fechaActual()); fragment.setArguments(parametro); fragmentTransaction.replace(R.id.frame, fragment); fragmentTransaction.commit(); return true; case R.id.direccion: parametro.putString("direccion","Ha seleccionado la opción: " + getResources().getString(R.string.direccion) + " --> " + getResources().getString(R.string.url)); fragment.setArguments(parametro); fragmentTransaction.replace(R.id.frame, fragment); fragmentTransaction.commit(); return true; case R.id.noticias: parametro.putString("noticias","Ha seleccionado la opción: " + getResources().getString(R.string.noticias) + " --> " + getResources().getString(R.string.noticias_info)); fragment.setArguments(parametro); fragmentTransaction.replace(R.id.frame, fragment); fragmentTransaction.commit(); return true; case R.id.email: parametro.putString("email","Ha seleccionado la opción: " + getResources().getString(R.string.email) + " --> " + getResources().getString(R.string.email_info)); fragment.setArguments(parametro); /*Se sustituye el frame definido en la Activity por el fragment.*/ fragmentTransaction.replace(R.id.frame, fragment); fragmentTransaction.commit(); return true; default: parametro.putString("default","Opción por defecto: " + getResources().getString(R.string.sindatos)); fragment.setArguments(parametro); fragmentTransaction.replace(R.id.frame, fragment); fragmentTransaction.commit(); return true; } } }); |
Se asigna la variable de tipo DrawerLayout
con su control a nivel de layout, además de inicializar un ActionBarDrawerToggle
:
1 2 3 |
drawerLayout = (DrawerLayout) findViewById(R.id.drawer); ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.abrirDrawer, R.string.cerrarDrawer){ |
Método que será llamado cuando se cierre el drawer:
1 2 3 4 5 6 |
@Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); } |
Método que será llamado cuando se abra el drawer:
1 2 3 4 5 6 7 |
@Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); } }; |
Se establece un control que notificará de los eventos del drawer:
1 2 |
drawerLayout.setDrawerListener(actionBarDrawerToggle); |
Se invoca al método syncState()
, que sincronizará el estado del drawer con el DrawerLayout
:
1 2 3 |
actionBarDrawerToggle.syncState(); } |
Por último se define un método que devolverá la fecha y hora actual, que formará parte de la funcionalidad de uno de los elementos del menú de navegación:
1 2 3 4 5 6 7 8 |
public String fechaActual() { Date fecha = new Date(); DateFormat formatoHora = new SimpleDateFormat("dd/MM/yyyy hh:MM:ss"); return formatoHora.format(fecha); } |
NavigationView\app\src\main\java\com\academiaandroid\navigationview\FragmentSeleccion.java
Clase FragmentSeleccion
, que hereda de la clase Fragment
, y que permite definir una parte independiente que puede añadirse al resto de elementos de la Activity donde se integra:
1 2 3 4 5 6 7 8 9 10 11 |
public class FragmentSeleccion extends Fragment { private TextView tvSeleccion; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_listado,container,false); if(v != null) { |
Se asigna a la variable de tipo TextView la referencia al control a nivel de layout:
1 2 |
tvSeleccion = (TextView) v.findViewById(R.id.tvSeleccion); |
Se recoge el elemento seleccionado por el usuario en el menú de navegación:
1 2 3 4 5 6 7 |
String ajustes = getArguments().getString("ajustes"); String direccion = getArguments().getString("direccion"); String calendario = getArguments().getString("calendario"); String noticias = getArguments().getString("noticias"); String email = getArguments().getString("email"); String sinInfo = getArguments().getString("default"); |
Se evalúa la selección del usuario para mostrar la información en el control TextView
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
if(ajustes != null) { tvSeleccion.setText(ajustes); }else if(direccion != null) { tvSeleccion.setText(direccion); }else if(calendario != null) { tvSeleccion.setText(calendario); }else if(noticias != null) { tvSeleccion.setText(noticias); }else if(email != null) { tvSeleccion.setText(email); }else if(sinInfo != null) { tvSeleccion.setText(sinInfo); } } return v; } |
NavigationView\app\src\main\res\layout\activity_main.xml
Layout principal, que implementa la estructura del menú de navegación desde el punto de vista visual.
Como se puede apreciar este layout utilizará como contenedor principal una vista personalizada con el widget DrawerLayout
. Dicho layout contendrá tanto el layout de la barra de herramientas, como un FrameLayout
que será sustituido por el Fragment
personalizado, además del NavigationView
(si se revisa la propiedad app:menu
de este último control, se define un menú personalizado en los recursos de la aplicación).
Comentar finalmente como este layout define el atributo android:layout_gravity="start"
, dentro del NavigationView
, y que permitirá mostrar el menú en la parte izquierda de la pantalla (si en lugar de ‘start’ utilizamos el valor ‘end’, se mostrará a la derecha):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".MainActivity"> <LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" > <include android:id="@+id/toolbar" layout="@layout/barrasuperior" /> <FrameLayout android:id="@+id/frame" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_height="match_parent" android:layout_width="wrap_content" android:layout_gravity="start" app:headerLayout="@layout/cabecera" app:menu="@menu/menu_navigation" /> </android.support.v4.widget.DrawerLayout> |
NavigationView\app\src\main\res\layout\cabecera.xml
Layout cabecera.xml
, que establece la imagen situada en la parte superior del menú de navegación, donde además se implementan dos controles TextView
con datos del usuario::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="190dp" android:background="@drawable/background_material" android:orientation="vertical"> <de.hdodenhof.circleimageview.CircleImageView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/profile_image" android:layout_width="76dp" android:layout_height="76dp" android:src="@drawable/g4582" app:border_color="#FF000000" android:layout_marginLeft="24dp" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginStart="24dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/academia" android:textSize="14sp" android:textColor="#FFF" android:textStyle="bold" android:gravity="left" android:paddingBottom="4dp" android:id="@+id/tvAcademiaAndroid" android:layout_above="@+id/tvPagAcademia" android:layout_alignLeft="@+id/profile_image" android:layout_alignStart="@+id/profile_image" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/url" android:id="@+id/tvPagAcademia" android:gravity="left" android:layout_marginBottom="8dp" android:textSize="14sp" android:textColor="#fff" android:layout_alignParentBottom="true" android:layout_alignLeft="@+id/tvAcademiaAndroid" android:layout_alignStart="@+id/tvAcademiaAndroid" /> </RelativeLayout> |
NavigationView\app\src\main\res\layout\fragment_listado.xml
Layout que permitirá mostrar el contenido del elemento seleccionado por el usuario en el componente NavigationView
. Dicha información se representará en un control TextView
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#1623d257"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="@string/seleccion" android:id="@+id/tvSeleccionInfo" android:layout_marginTop="44dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:textStyle="bold" android:layout_marginLeft="10dp" android:layout_alignParentStart="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/sindatos" android:id="@+id/tvSeleccion" android:layout_below="@+id/tvSeleccionInfo" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:textColor="#196ef3" android:textStyle="bold" android:layout_marginLeft="10dp" /> </RelativeLayout> |
NavigationView\app\src\main\res\layout\barrasuperior.xml
Como particularidad dentro de este layout se establece la propiedad background a partir de un recurso creado en la ruta NavigationView\app\src\main\res\values\colores.xml. Además como se puede apreciar se define una barra de herramientas para utilizar dentro de la aplicación:
1 2 3 4 5 6 7 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" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:background="@color/primaryColor"/> |
NavigationView\app\src\main\res\menu\menu_navigation.xml
Para definir el contenido del NavigationView
, se creará un archivo de recursos de menú, donde además de establecer los strings que se visualizarán en el menú, también se asignará las imágenes asociadas a cada elemento:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/ajustes" android:checked="false" android:icon="@drawable/ajustes_24dp" android:title="@string/ajustes" /> <item android:id="@+id/calendario" android:checked="false" android:icon="@drawable/calendario_24dp" android:title="@string/calendario" /> <item android:id="@+id/direccion" android:checked="false" android:icon="@drawable/direccion_24dp" android:title="@string/direccion" /> <item android:id="@+id/noticias" android:checked="false" android:icon="@drawable/noticia_24dp" android:title="@string/noticias" /> <item android:id="@+id/email" android:checked="false" android:icon="@drawable/mail_24dp" android:title="@string/email" /> </group> </menu> |
Dependencias Gradle implementadas (módulo app)
Será necesario añadir las dependencias para soporte de material design:
1 2 3 4 5 6 7 8 9 10 |
dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.1' compile 'de.hdodenhof:circleimageview:1.3.0' compile 'com.android.support:design:23.1.1' } |
Descarga del proyecto
Pulsa para descargar el proyecto completo:
Download