El componente Navigation de la arquitectura simplifica la implementación de la navegación y, al mismo tiempo, te ayuda a visualizar el flujo de navegación de tu app. La biblioteca proporciona una serie de beneficios, entre ellos, los siguientes:
- Control automático de las transacciones de fragmentos.
- Controla correctamente las acciones Arriba y Atrás de forma predeterminada.
- Comportamientos predeterminados para las animaciones y las transiciones.
- Vínculos directos como operación de primer nivel.
- Implementación de patrones de la IU de navegación (como paneles laterales de navegación y navegación inferior) con poco esfuerzo adicional.
- Seguridad de tipo en el paso de información cuando se navega.
- Herramientas de Android Studio para visualizar y editar el flujo de navegación de una app.
Actividades
En este codelab, trabajarás con la app de ejemplo que aparece a continuación:
Ya se crearon todas las actividades y los fragmentos por ti. Utilizarás el componente Navigation para conectarlos y, mientras lo hagas, pondrás en práctica lo siguiente:
- Gráfico de navegación visual
- Navegación por destino y acción
- Animaciones de transición
- Navegación por menú, navegación inferior y navegación por paneles laterales de menú
- Seguridad de tipo en el pase de argumentos
- Vínculos directos
Requisitos previos
- Conocimientos básicos de Kotlin (este codelab está en Kotlin)
- Android Studio 3.2 o una versión posterior
- Emulador o dispositivo con API 14 o posterior
Obtén el código
Clona el codelab de navegación de GitHub:
$ git clone https://github.com/googlecodelabs/android-navigation
De manera alternativa, puedes descargar el repositorio en un archivo ZIP:
Obtén Android Studio 3.3 o una versión posterior
Asegúrate de usar Android Studio 3.3 o una versión posterior, ya que las herramientas de navegación de Android Studio así lo requieren.
Si necesitas descargar una versión reciente de Android Studio, puedes hacerlo aquí.
Descripción general de Navigation
El componente Navigation consta de tres partes clave que trabajan juntas en armonía. Son las siguientes:
- Gráfico de navegación (nuevo recurso XML): Es un recurso que contiene toda la información relacionada con la navegación en una ubicación centralizada. Esto incluye todos los lugares de tu app, conocidos como destinos, y las posibles rutas que puede seguir un usuario para llegar a ellos con tu app.
- NavHostFragment (vista de diseño XML): Es un widget especial que agregas a tu diseño y que muestra diferentes destinos del gráfico de navegación.
- NavController (objeto Kotlin/Java): Es un objeto que realiza un seguimiento de la posición actual en el gráfico de navegación. Organiza el intercambio de contenido de destino en el
NavHostFragment
a medida que te desplazas por el gráfico.
Cuando navegues, usarás el objeto NavController y le indicarás a dónde quieres desplazarte o qué ruta quieres seguir en el gráfico de navegación. Luego, NavController
mostrará el destino apropiado en el NavHostFragment.
Esa es la idea básica. Veamos esto en la práctica. Comencemos con el nuevo recurso del gráfico de navegación.
Destinos
El componente Navigation presenta el concepto de destino. Un destino es cualquier lugar al que puedas navegar en tu app, por lo general, un fragmento o una actividad. Esta función está disponible de inmediato, pero también puedes crear tus propios tipos de destino personalizados si lo necesitas.
Gráfico de navegación
Un gráfico de navegación es un tipo de recurso nuevo que define todas las rutas posibles que puede tomar un usuario en una app. Muestra de forma gráfica todos los destinos a los que se puede llegar desde un destino determinado. Android Studio muestra el gráfico en el editor de navegación. A continuación, puedes ver una parte del gráfico de navegación inicial que crearás para tu app:
Cómo explorar el editor de navegación
1. Abrir res/navigation/mobile_navigation.xml
2. Haz clic en Design para ir al modo de diseño:
Deberías ver lo siguiente:
El gráfico de navegación muestra los destinos disponibles. Las flechas entre los destinos se denominan acciones. Más adelante, obtendrás más información sobre las acciones.
3. Haz clic en un destino para ver sus atributos.
4. Haz clic en cualquier acción, representada con una flecha, para ver sus atributos.
Anatomía de un archivo de navegación en formato XML
Todos los cambios que realices en el editor de navegación gráfica cambian el archivo XML subyacente, de forma parecida a la manera en la que el editor de diseño modifica el XML de diseño.
Haz clic en la pestaña Text:
Verás algunos XML como este:
<navigation 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"
app:startDestination="@+id/home_dest">
<!-- ...tags for fragments and activities here -->
</navigation>
Ten en cuenta que:
<navigation>
es el nodo raíz de cada gráfico de navegación.<navigation>
contiene uno o más destinos, representados con elementos<activity>
o<fragment>
.app:startDestination
es un atributo que especifica el destino que se inicia de forma predeterminada cuando el usuario abre la app por primera vez.
Veamos un destino de fragmento:
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
</action>
</fragment>
Ten en cuenta que:
android:id
define un ID para el fragmento, que puedes usar en otra parte del archivo XML y de tu código para hacer referencia al destino.android:name
declara el nombre de clase completamente calificado del fragmento para crear una instancia cuando navegas a ese destino.tools:layout
especifica cuál es el diseño que se debe mostrar en el editor gráfico.
Algunas etiquetas <fragment>
también contienen objetos <action>
, <argument>,
y <deepLink>
, que analizaremos más adelante.
La app de ejemplo comienza con algunos destinos en el gráfico. En este paso, agregarás un destino nuevo. Antes de poder navegar al gráfico de navegación, debes agregar un destino que te lleve a él.
1. Abre res/navigation/mobile_navigation.xml
y haz clic en la pestaña Design.
2. Haz clic en el ícono New Destination y selecciona "settings_fragment".
El resultado es un nuevo destino, que presenta una vista previa del diseño del fragmento en la vista de diseño.
Ten en cuenta que también puedes editar directamente el archivo XML para agregar destinos:
mobile_navigation.xml
<fragment
android:id="@+id/settings_dest"
android:name="com.example.android.codelabs.navigation.SettingsFragment"
android:label="@string/settings"
tools:layout="@layout/settings_fragment" />
Ahora tienes este increíble gráfico de navegación, pero en realidad no lo estás utilizando para navegar.
Actividades y navegación
El componente Navigation sigue las pautas descritas en los Principios de Navigation. Los Principios de Navigation te recomiendan que uses actividades como puntos de entrada para tu app. Las actividades también incluyen navegación global, como la barra de navegación inferior.
Por otro lado, los fragmentos serán, en realidad, los diseños específicos del destino.
A fin de que todo esto funcione, debes modificar los diseños de tu actividad para que contengan un widget especial llamado NavHostFragment
. Un NavHostFragment
se encarga de intercambiar los diferentes destinos de fragmentos dentro y fuera a medida que navegas por el gráfico de navegación.
Un diseño simple que admite una navegación, parecido al de la imagen de arriba, se ve de esta manera. Puedes encontrar un ejemplo de este código en res/layout-470dp/navigation_activity.xml
:
<LinearLayout
.../>
<androidx.appcompat.widget.Toolbar
.../>
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/mobile_navigation"
app:defaultNavHost="true"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</LinearLayout>
Ten en cuenta que:
- Este es el diseño de una actividad y contiene navegación global, incluidas una barra de navegación inferior y una barra de herramientas.
android:name="androidx.navigation.fragment.NavHostFragment"
yapp:defaultNavHost="true"
conectan el botón Atrás del sistema alNavHostFragment
.app:navGraph="@navigation/mobile_navigation"
asocia elNavHostFragment
a un gráfico de navegación. Este gráfico de navegación especifica todos los destinos a los que el usuario puede navegar en esteNavHostFragment
.
NavController
Por último, cuando un usuario realiza una acción, como hacer clic en un botón, debe activarse un comando de navegación. Una clase especial llamada NavController
es la que activa el intercambio de fragmentos en el NavHostFragment
.
// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)
Ten en cuenta que, para navegar, se pasa un ID de destino o de acción. Estos son los ID definidos en el XML del gráfico de navegación. Este es un ejemplo de cómo pasar un ID de destino.
NavController
es potente porque cuando llamas a métodos como navigate()
o popBackStack(),
, convierte esos comandos en las operaciones de framework correspondientes según el tipo de destino al que navegas o del que navegas. Por ejemplo, cuando llamas a navigate()
con un destino de actividad, NavController
llama a startActivity()
por ti.
Existen algunas formas de obtener un objeto NavController
asociado a tu NavHostFragment
. En Kotlin, se recomienda que uses una de las siguientes funciones de extensión, según llames al comando de navegación desde un fragmento, una actividad o una vista:
Cómo navegar a un destino con NavController
Es tu turno de navegar con NavController
. Conecta el botón Navigate to Destination para navegar al destino flow_step_one_dest
(que es un FlowStepFragment
):
1. Abre HomeFragment.kt
.
2. Conecta navigate_destination_button
con onViewCreated()
.
HomeFragment.kt
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest, null)
}
3. Ejecuta la app y haz clic en el botón Navigate to Destination. Ten en cuenta que el botón navega al destino flow_step_one_dest
.
El código del objeto de escucha de clics se vería de la siguiente manera:
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.flow_step_one_dest, null)
)
Cada llamada a navigate()
tiene una transición predeterminada no muy emocionante asociada, como se muestra a continuación:
La transición predeterminada y otros atributos asociados a la llamada pueden anularse con la inclusión de un conjunto de NavOptions
. NavOptions
usa un patrón Builder
que permite anular y configurar solo las opciones que necesitas. También hay una DSL ktx para NavOptions, que es lo que usarás.
Para las transiciones animadas, puedes definir recursos de animación XML en la carpeta de recursos anim
y, luego, usar esas animaciones en las transiciones. Se incluyen algunos ejemplos en el código de la app.
Cómo agregar una transición personalizada
Actualiza el código para que muestre una animación de transición personalizada cuando se presione el botón Navigate to Destination.
1. Abre HomeFragment.kt
.
2. Define un elemento NavOptions
y pásalo a la llamada de navigate()
a navigate_destination_button
.
val options = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
view.findViewById<Button>(R.id.navigate_destination_button)?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest, null, options)
}
3. Si todavía no lo hiciste, quita el código que se agregó en el paso 5.
4. Verifica que el fragmento se deslice hacia la pantalla cuando presionas el botón Navigate To Destination y que salga de ella cuando presionas Atrás.
Acciones
El sistema de navegación también te permite navegar a través de las acciones. Como se mencionó anteriormente, las líneas que se muestran en el gráfico de navegación son representaciones visuales de las acciones.
La navegación por acciones tiene los siguientes beneficios sobre la navegación por destino:
- Puedes visualizar las rutas de navegación de tu app.
- Las acciones pueden contener atributos asociados adicionales que puedes configurar, como una animación de transición, valores de argumentos y comportamiento de la pila de actividades.
- Para navegar, puedes usar Safe Args del complemento, que verás en breve.
Estas son las imágenes y el XML para la acción que conecta flow_step_one_dest
con flow_step_two_dest
:
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
</action>
</fragment>
<fragment
android:id="@+id/flow_step_two_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<!-- ...removed for simplicity-->
</fragment>
Ten en cuenta que:
- Las acciones se anidan dentro del destino, que es desde el que navegarás.
- La acción incluye un argumento de destino que hace referencia a flow_step_two_dest, que es el ID de la página a la que navegarás.
- El ID de la acción es "next_action".
A continuación, se muestra otro ejemplo de la acción que conecta flow_step_two_dest
con home_dest
:
<fragment
android:id="@+id/home_dest"
android:name="com.example.android.codelabs.navigation.HomeFragment"
.../>
<fragment
android:id="@+id/flow_step_two_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment">
<argument
.../>
<action
android:id="@+id/next_action"
app:popUpTo="@id/home_dest">
</action>
</fragment>
Ten en cuenta que:
- Se usa el mismo ID next_action para la acción que conecta
flow_step_two_dest
conhome_dest
. Con este ID, puedes navegar tanto desdeflow_step_one_dest
, como desdeflow_step_two_dest
. Este es un ejemplo de cómo las acciones pueden proporcionar un nivel de abstracción y te permiten navegar a un lugar diferente según el contexto. - Se usa el atributo
popUpTo
; esta acción quitará fragmentos de la pila de actividades hasta llegar ahome_dest
.
Cómo navegar con una acción
Es hora de conectar el botón Navigate with Action para que navegue con una acción.
1. Abre el archivo mobile_navigation.xml
en el modo Design.
2. Arrastra una flecha de home_dest
a flow_step_one_dest
:
3. Con la flecha de acción seleccionada (azul), cambia las propiedades de la acción para que:
- El ID sea next_action.
- La transición de entrada sea slide_in_right.
- La transición de salida sea slide_out_left.
- La transición de entrada de la ventana emergente sea slide_in_left.
- La transición de salida de la ventana emergente sea slide_out_right.
4. Haz clic en la pestaña Text.
Verás que se agregó una acción next_action
nueva al destino home_dest
.
mobile_navigation.xml
<fragment android:id="@+id/home_dest"
...>
<action android:id="@+id/next_action"
app:destination="@+id/flow_step_one"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
5. Abre HomeFragment.kt
.
6. Agrega un objeto de escucha de clics al navigate_action_button
.
HomeFragment.kt
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.next_action, null)
)
7. Verifica que, cuando presiones Navigate to Action, ahora se navegue a la siguiente pantalla.
Safe Args
El componente Navigation tiene un complemento de Gradle llamado Safe Args, que genera clases simples de objeto y compilador para el acceso con seguridad de tipos a argumentos específicos de destinos y acciones.
Safe Args te permite deshacerte de código como este cuando pasas valores entre destinos:
val username = arguments?.getString("usernameKey")
En lugar de eso, puedes reemplazarlo por código que haya generado métodos set y get.
val username = args.username
Cómo pasar un valor con Safe Args
1. Abre el archivo build.gradle
del proyecto y observa el complemento Safe Args:
build.gradle
dependencies {
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
//...
}
2. Abre el archivo app/build.gradle
y observa el complemento aplicado:
app/build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs.kotlin'
android {
//...
}
3. Abre mobile_navigation.xml,
y observa cómo se definen los argumentos del destino flow_step_one_dest
.
mobile_navigation.xml
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="1"/>
<action...>
</action>
</fragment>
Con la etiqueta <argument>
, Safe Args genera una clase llamada FlowStepFragmentArgs
.
Dado que el archivo XML incluye un argumento llamado flowStepNumber
, especificado por android:name="flowStepNumber"
, la clase FlowStepFragmentArgs
generada incluirá una variable flowStepNumber
con métodos get y set.
4. Abre FlowStepFragment.kt
.
5. Comenta la línea de código que se muestra a continuación:
FlowStepFragment.kt
// Comment out this line
// val flowStepNumber = arguments?.getInt("flowStepNumber")
Este código anticuado no cuenta con seguridad de tipos, por lo que es mejor usar Safe Args.
6. Actualiza FlowStepFragment
para usar la clase FlowStepFragmentArgs
generada con el código. Se obtendrán los argumentos FlowStepFragment
con seguridad de tipos.
FlowStepFragment.kt
val safeArgs: FlowStepFragmentArgs by navArgs()
val flowStepNumber = safeArgs.flowStepNumber
Clases Directions de Safe Args
También puedes usar Safe Args para navegar con seguridad de tipo, ya sea que agregues argumentos o no. Esto se hace con las clases Directions generadas.
Las clases Directions se generan para todos los diferentes destinos con acciones. La clase Directions incluye métodos para cada acción que un destino tenga.
Por ejemplo, el objeto de escucha de clics navigate_action_button
en HomeFragment.kt podría cambiarse a:
HomeFragment.kt
// Note the usage of curly braces since we are defining the click listener lambda
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener {
val flowStepNumberArg = 1
val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
findNavController().navigate(action)
}
NavigationUI y navigation-ui-ktx
Los componentes Navigation incluyen una clase NavigationUI
y las extensiones de Kotlin navigation-ui-ktx
. NavigationUI
tiene métodos estáticos que asocian elementos de menú con destinos de navegación, y navigation-ui-ktx
es un conjunto de funciones de extensión que hacen lo mismo. Si NavigationUI
encuentra un elemento de menú con el mismo ID que el de un destino del gráfico actual, lo configurará para navegar a ese destino.
Cómo usar NavigationUI con un menú de opciones
Una de las formas más fáciles de usar NavigationUI es hacer que simplifique la configuración del menú de opciones. En particular, NavigationUI hace que sea más sencillo controlar la devolución de llamada a onOptionsItemSelected
.
1. Abre MainActivity.kt.
Verás que ya tienes el código para aumentar el menú overflow_menu
en onCreateOptionsMenu
2. Abre res/menu/overflow_menu.xml
.
3. Actualiza el menú ampliado para que incluya settings_dest
.
overflow_menu.xml
<item
android:id="@+id/settings_dest"
android:icon="@drawable/ic_settings"
android:menuCategory="secondary"
android:title="@string/settings" />
4. Abre MainActivity.kt
.
5. Haz que NavigationUI controle onOptionsItemSelected
con el método de ayuda onNavDestinationSelected
. Si no se supone que el elemento del menú navegue, adminístralo con super.onOptionsItemSelected
.
MainActivity.kt
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
|| super.onOptionsItemSelected(item)
}
6. Ejecuta la app. Debes tener un menú ActionBar funcional que navegue al SettingsFragment.
Cómo usar NavigationUI para configurar la navegación inferior
El código ya contiene el código de diseño XML para implementar la navegación inferior. Por este motivo, puedes ver la barra de navegación inferior. Sin embargo, no navega a ningún lugar.
1. Abre res/layout/navigation_activity/navigation_activity.xml (h470dp)
y haz clic en la pestaña Text.
Verás que el código de diseño XML para la navegación inferior se encuentra allí y hace referencia a bottom_nav_menu.xml
.
navigation_activity.xml (h470dp)
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/bottom_nav_menu" />
2. Abre res/menu/bottom_nav_menu.xml
.
Verás que hay dos elementos para la navegación inferior y que sus ID coinciden con los de los destinos del gráfico de navegación:
bottom_nav_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@id/home_dest"
android:icon="@drawable/ic_home"
android:title="@string/home" />
<item
android:id="@id/deeplink_dest"
android:icon="@drawable/ic_android"
android:title="@string/deeplink" />
</menu>
Hagamos que la navegación inferior realice una acción con la NavigationUI.
3. Abre MainActivity.kt
.
4. Implementa el método setupBottomNavMenu
con setupWithNavController(bottomNavigationView: BottomNavigationView, navController: NavController)
.
MainActivity.kt
private fun setupBottomNavMenu(navController: NavController) {
val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
bottomNav?.setupWithNavController(navController)
}
Ahora funciona la navegación inferior.
Cómo usar NavigationUI para configurar un panel lateral de navegación
Por último, usemos NavigationUI
para configurar la navegación lateral y el panel lateral de navegación, incluido el control de la ActionBar y la navegación hacia arriba correcta. Verás esta opción si tienes una pantalla lo suficientemente grande o si la pantalla es demasiado corta para la navegación inferior.
Primero, observa que el código XML de diseño ya está en la app.
1. Abre navigation_activity.xml
y navigation_activity.xml (w960dp)
.
Observa cómo ambos diseños contienen una NavigationView conectada al nav_drawer_menu. En la versión para tablets (w960dp), NavigationView está siempre en la pantalla. En dispositivos más pequeños, se anida en un DrawerLayout.
Ahora, comencemos a implementar la navegación de NavigationView
.
2. Abre MainActivity.kt
.
3. Implementa el método setupNavigationMenu
con setupWithNavController(navigationView: NavigationView, navController: NavController)
. Observa cómo esta versión del método toma un NavigationView
y no un BottomNavigationView
.
MainActivity.kt
private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView?.setupWithNavController(navController)
}
A continuación, se mostrará en la pantalla el menú de vista de navegación, pero no afectará la ActionBar.
Para configurar ActionBar
, debes crear una instancia de AppBarConfiguration
. El objetivo de AppBarConfiguration
es especificar las opciones de configuración que deseas para tus barras de herramientas, contraer barras de herramientas y barras de acciones. Entre las opciones de configuración, se incluye si la barra debe procesar un diseño de panel lateral y qué destinos se consideran de nivel superior.
Los destinos de nivel superior son los destinos de nivel raíz de tu app. No muestran un botón "Arriba" en la barra de la app, sino que exhiben el ícono del panel lateral si el destino usa un diseño de panel lateral.
4. Pasa un conjunto de ID de destino de nivel superior y el diseño del panel lateral para crear un AppBarConfiguration
.
MainActivity.kt
val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.home_dest, R.id.deeplink_dest),
drawerLayout)
Ahora que tienes una AppBarConfiguration, puedes llamar a NavigationUI.setupActionBarWithNavController
. Esta acción hará lo siguiente:
- Mostrará un título en la ActionBar según la etiqueta de destino.
- Mostrará el botón Arriba cuando no te encuentres en un destino de nivel superior.
- Mostrará un ícono de panel lateral (ícono de opciones) cuando estés en un destino de nivel superior.
5. Implementa setupActionBarWithNavController
.
MainActivity.kt
private fun setupActionBar(navController: NavController,
appBarConfig : AppBarConfiguration) {
setupActionBarWithNavController(navController, appBarConfig)
}
También deberías hacer que NavigationUI controle lo que sucede cuando se presiona el botón Arriba.
6. Anula onSupportNavigationUp
y llama a NavigationUI.navigateUp
con el mismo AppBarConfiguration
.
MainActivity.kt
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}
7. Ejecuta tu código. Si abres la app en una pantalla dividida, deberías tener un panel lateral de navegación en funcionamiento. El ícono Arriba y el panel lateral deben aparecer en los momentos adecuados y funcionar correctamente.
Agregar destinos nuevos a una NavigationView
es sencillo. Una vez que tu panel lateral de navegación funcione con la navegación hacia arriba y hacia atrás, solo resta agregar el elemento de menú nuevo.
8. Abrir menu/nav_drawer_menu.xml
9. Agrega un elemento de menú nuevo para settings_dest
.
nav_drawer_menu.xml
<item
android:id="@+id/settings_dest"
android:icon="@drawable/ic_settings"
android:title="@string/settings" />
Ahora el panel lateral de navegación muestra la pantalla de configuración como un destino. ¡Buen trabajo!
Vínculos directos y navegación
Los componentes de navegación también incluyen compatibilidad con vínculos directos. Los vínculos directos son una forma de saltar al centro de la navegación de tu app, ya sea desde una URL real o un intent pendiente de una notificación.
Un beneficio de usar la biblioteca de navegación para controlar vínculos directos es que garantiza que los usuarios comiencen con el destino correcto y con la pila de actividades adecuada desde otros puntos de entrada, como widgets de la app, notificaciones o vínculos web (esto se explica en el próximo paso).
Navigation proporciona una clase NavDeepLinkBuilder
para compilar un PendingIntent
que llevará al usuario a un destino específico.
Cómo agregar un vínculo directo
Usaremos el NavDeepLinkBuilder
para conectar el widget de una app con un destino.
1. Abre DeepLinkAppWidgetProvider.kt
.
2. Agrega un PendingIntent
construido con NavDeepLinkBuilder
:
DeepLinkAppWidgetProvider
val args = Bundle()
args.putString("myarg", "From Widget");
val pendingIntent = NavDeepLinkBuilder(context)
.setGraph(R.navigation.mobile_navigation)
.setDestination(R.id.deeplink_dest)
.setArguments(args)
.createPendingIntent()
remoteViews.setOnClickPendingIntent(R.id.deep_link_button, pendingIntent)
Ten en cuenta que:
setGraph
incluye el gráfico de navegación.setDestination
especifica a dónde te llevará el vínculo.setArguments
incluye los argumentos que desees pasar a tu vínculo directo.
3. Agrega el widget de vínculo directo a la pantalla principal. Mantén presionada la pantalla principal para ver la opción de agregar un widget.
Mantén presionado. |
Desplázate hacia abajo hasta encontrar el widget. |
Cuando termines, tendrás un widget de vínculo directo.
4. Presiona el widget y verifica que el destino de Android se abra con el argumento correcto. Debería decir "From Widget" en la parte superior, ya que ese es el argumento que pasaste en DeepLinkAppWidgetProvider.
5. Verifica que presionar el botón Atrás te dirija al destino home_dest
.
Pila de actividades de vínculo directo
La pila de actividades de un vínculo directo se determina mediante el gráfico de navegación que pasas. Si la actividad explícita que elegiste tiene una actividad superior, también se incluye esa actividad superior.
La pila de actividades se genera con los destinos que se especificaron con app:startDestination
. En esta app, solo tenemos una actividad y un nivel de navegación, por lo que la pila de actividades te llevará al destino home_dest
.
La navegación más complicada puede incluir gráficos de navegación anidados. El app:startDestination
de cada nivel de los gráficos anidados determina la pila de actividades. Para obtener más información sobre los vínculos directos y los gráficos anidados, consulta los Principios de Navigation.
El elemento <deepLink>
Uno de los usos más comunes de un vínculo directo es permitir que un vínculo web abra una actividad en tu app. Tradicionalmente, usarías un filtro de intent y asociarías una URL con la actividad que deseas abrir.
La biblioteca de navegación hace que esto sea muy simple y te permite asignar URL directamente a destinos en tu gráfico de navegación.
<deepLink>
es un elemento que puedes agregar a un destino en el gráfico. Cada elemento <deepLink>
tiene un solo atributo obligatorio: app:uri
.
Además de la coincidencia con un URI directo, se admiten las siguientes funciones:
- Se supone que los URI sin esquema son "http" y "https". Por ejemplo,
www.example.com
coincidirá conhttp://www.example.com
yhttps://www.example.com
. - Puedes usar marcadores de posición en forma de
{placeholder_name}
para hacer coincidir uno o más caracteres. El valor de string del marcador de posición estará disponible en el conjunto de argumentos que tenga una clave con el mismo nombre. Por ejemplo,http://www.example.com/users/{id}
coincidirá conhttp://www.example.com/users/4
. - Puedes usar el comodín
.*
para hacer coincidir 0 o más caracteres. - NavController controlará automáticamente los intents ACTION_VIEW y buscará vínculos directos que coincidan.
Cómo agregar un vínculo directo basado en URI con <deepLink>
En este paso, agregarás un vínculo directo a www.example.com.
1. Abre mobile_navigation.xml
.
2. Agrega un elemento <deepLink>
al destino deeplink_dest
.
mobile_navigation.xml
<fragment
android:id="@+id/deeplink_dest"
android:name="com.example.android.codelabs.navigation.DeepLinkFragment"
android:label="@string/deeplink"
tools:layout="@layout/deeplink_fragment">
<argument
android:name="myarg"
android:defaultValue="Android!"/>
<deepLink app:uri="www.example.com/{myarg}" />
</fragment>
3. Abre AndroidManifest.xml
.
4. Agrega la etiqueta nav-graph
. Eso garantizará que se genere el filtro de intents adecuado.
AndroidManifest.xml
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<nav-graph android:value="@navigation/mobile_navigation" />
</activity>
5. Inicia tu app con un vínculo directo. Existen dos maneras de hacerlo:
- Usa
adb
:
adb shell am start -a android.intent.action.VIEW -d "http://www.example.com/urlTest"
- Navega con Google app. Debería permitirte colocar www.example.com/urlTest en la barra de búsqueda para que aparezca la ventana de desambiguación. Selecciona Codelab de Navigation.
Se abrió con la barra de búsqueda (no se encuentra en Chrome). |
Diálogo de desambiguación. |
En cualquier caso, deberías ver en la pantalla el mensaje "urlTest", que se pasó a través del fragmento, desde la URL.
Hay una parte más de la app del codelab que puedes usar para experimentar: el botón del carrito de compras.
Este es un resumen de las habilidades que aprendiste en este codelab. Este paso no incluye comentarios, así que pruébalo por tu cuenta:
- Crea una clase nueva de fragmento.
- Agrega el fragmento como destino a tu gráfico de navegación.
- Haz que el ícono del carrito de compras abra la clase nueva de fragmento con NavigationUI para controlar el menú.
Ya estás familiarizado con los conceptos básicos del componente Navigation. En este codelab, aprendiste lo siguiente:
- La estructura del gráfico de navegación
- NavHostFragment y NavController
- Cómo navegar a destinos específicos
- Cómo navegar por acciones
- Cómo pasar argumentos entre destinos, incluido el uso del nuevo complemento Safe Args
- Navegación con menús, navegaciones inferiores y paneles laterales de navegación
- Navegación con vínculos directos
Puedes seguir explorando con esta app o comenzar a usar la navegación en la tuya.
Hay mucho más para probar, como por ejemplo:
- Destinos emergentes de la pila de actividades (o cualquier manipulación de pila de actividades)
- Gráficos de navegación anidados
- Navegación condicional
- Cómo agregar compatibilidad con nuevos destinos
Para obtener más información sobre el componente Navigation, consulta la documentación. Si te interesa obtener más información sobre otros componentes de la arquitectura, prueba los siguientes codelabs:
- Codelab de Room con un componente View (LiveData, ViewModel y Room)
- Codelab de WorkManager de Android
- Codelab de Paging de Android
- Codelab de componentes optimizados para el ciclo de vida de Android (LiveData y ViewModel)
- Codelab de Persistence de Android (Room)