Componente Navigation de Jetpack

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:

Descargar 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:

  1. 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.
  2. 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.
  3. 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.

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:

Página principal, paso uno y paso dos

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" y app:defaultNavHost="true" conectan el botón Atrás del sistema al NavHostFragment.
  • app:navGraph="@navigation/mobile_navigation" asocia el NavHostFragment 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 este NavHostFragment.

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:

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:

Desde la página principal, el usuario hace clic en Navigation to destination y navega al paso uno.

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 con home_dest. Con este ID, puedes navegar tanto desde flow_step_one_dest, como desde flow_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 a home_dest.

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)
}

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.

<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.

<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!

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.

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.

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.

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á con http://www.example.com y https://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á con http://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.

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:

  1. Crea una clase nueva de fragmento.
  2. Agrega el fragmento como destino a tu gráfico de navegación.
  3. 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: