Navigation dans Jetpack

Le composant d’architecture de navigation simplifie l'implémentation de la navigation, tout en vous permettant de visualiser le flux de navigation de votre appli. Cette bibliothèque offre de nombreux avantages, tels que :

  • Gestion automatique des transactions de fragment
  • Gestion correcte des fonctions vers le haut et en arrière par défaut
  • Comportements par défaut des animations et des transitions
  • Liens profonds en tant qu'opérations de première classe
  • Implémentation aisée de modèles d'interface utilisateur de navigation (comme des panneaux de navigation et la barre de navigation inférieure)
  • Sûreté du typage lors de la transmission d'informations en cours de navigation
  • Outils Android Studio pour visualiser et modifier le flux de navigation d'une application

Objectifs de l'atelier

Dans cet atelier de programmation, vous allez utiliser l'exemple d'application présenté ci-dessous :

L'ensemble des activités et des fragments ont déjà été créés automatiquement. Vous utiliserez le composant de navigation pour les connecter et, ce faisant, implémenter les éléments suivants :

  • Graphique de navigation visuelle
  • Navigation par destination et par action
  • Animations de transition
  • Navigation dans le menu, barre de navigation inférieure et panneau de menus
  • Transmission d'arguments avec sûreté du typage
  • Liens profonds

Conditions préalables

  • Connaissances de base du langage Kotlin (cet atelier de programmation est écrit en Kotlin)
  • Android Studio version 3.2 ou ultérieure
  • Émulateur ou appareil exécutant la version 14 ou ultérieure de l'API

Obtenir le code

Clonez l'atelier de programmation sur la navigation à partir de GitHub :

$ git clone https://github.com/googlecodelabs/android-navigation

Vous pouvez également télécharger le dépôt sous la forme d'un fichier ZIP :

Télécharger le fichier ZIP

Obtenir Android Studio 3.3 ou version ultérieure

Assurez-vous d'utiliser Android Studio 3.3 ou version ultérieure, sans quoi vous ne pourrez pas utiliser les outils de navigation d'Android Studio.

Si vous devez télécharger une version récente d'Android Studio, cliquez ici.

Présentation de la navigation

Le composant de navigation est constitué de trois parties principales, qui fonctionnent en parfaite harmonie, à savoir :

  1. Graphique de navigation (nouvelle ressource XML) : cette ressource regroupe toutes les informations liées à la navigation dans un emplacement centralisé. Elle contient tous les emplacements de votre application, appelés destinations, ainsi que les chemins qu'un utilisateur peut emprunter via votre application.
  2. NavHostFragment (vue XML de mise en page) : widget spécial que vous ajoutez à votre mise en page. Ce widget affiche différentes destinations à partir de votre graphique de navigation.
  3. NavController (objet Kotlin/Java) : objet qui assure le suivi de la position actuelle au sein du graphique de navigation. Il orchestre le changement du contenu de destination dans NavHostFragment lorsque vous parcourez un graphique de navigation.

Au cours de la navigation, vous utiliserez l'objet NavController pour indiquer la destination souhaitée ou le chemin que vous souhaitez emprunter dans le graphique de navigation. NavController affiche alors la destination appropriée dans la vue NavHostFragment.

Voilà pour le concept de base du composant ! Voyons maintenant comme cela se présente dans la pratique, en commençant par la nouvelle ressource "Graphique de navigation".

Destinations

Le composant de navigation introduit le concept de destination. Une destination correspond à tout emplacement auquel vous pouvez accéder dans votre application ; il s'agit généralement d'un fragment ou d'une activité. La prise en charge des destinations est assurée par défaut, mais vous pouvez également créer vos propres types de destination personnalisés si nécessaire.

Un graphique de navigation est un nouveau type de ressource qui définit tous les chemins qu'un utilisateur peut emprunter dans une application. Il présente, sous forme visuelle, toutes les destinations accessibles à partir d'une destination donnée. Android Studio affiche ce graphique dans son éditeur de navigation. Voici une partie du graphique de navigation de démarrage que vous créerez pour votre application :

Accueil, Étape 1 et Étape 2

Explorer l'éditeur de navigation

1. Ouvrez res/navigation/mobile_navigation.xml.

2. Cliquez sur Design pour passer en mode Conception :

Vous devriez obtenir le graphique suivant :

Le graphique de navigation affiche les destinations disponibles. Les flèches entre les destinations sont appelées actions. Ces actions seront décrites plus en détail dans la suite de cet atelier.

3. Cliquez sur une destination pour en afficher les attributs.

4. Cliquez sur une action, représentée par une flèche, pour en afficher les attributs.

Anatomie d'un fichier XML de navigation

Toutes les modifications que vous effectuez dans l'éditeur de navigation graphique affectent le fichier XML sous-jacent, de la même façon que l'éditeur de mise en page modifie le fichier XML de mise en page.

Cliquez sur l'onglet Text (Texte) :

Du code XML s'affiche comme suit :

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

Remarques :

  • <navigation> est le nœud racine de chaque graphique de navigation.
  • <navigation> contient une ou plusieurs destinations, représentées par des éléments <activity> ou <fragment>.
  • app:startDestination est un attribut qui spécifie la destination lancée par défaut la première fois que l'utilisateur ouvre l'application.

Examinons une destination de fragment :

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

Remarques :

  • android:id définit un identifiant pour le fragment que vous pouvez utiliser pour référencer la destination à un autre endroit dans ce contenu XML et dans votre code.
  • android:name déclare le nom de classe complet du fragment à instancier lorsque vous accédez à cette destination.
  • tools:layout spécifie la mise en page à afficher dans l'éditeur graphique.

Certaines balises <fragment> contiennent également des balises <action>, <argument>, et <deepLink>, que nous aborderons dans la suite de cet atelier.

L'exemple d'application commence par quelques destinations du graphique. Au cours de cette étape, vous aurez l'occasion d'en ajouter une nouvelle. Vous devez ajouter une destination au graphique de navigation avant de pouvoir y accéder.

1. Ouvrez res/navigation/mobile_navigation.xml, puis cliquez sur l'onglet Design (Conception).

2. Cliquez sur l'icône Nouvelle destination, puis sélectionnez "settings_fragment".

Le résultat est une nouvelle destination, qui affiche un aperçu de la mise en page du fragment en mode Conception.

Notez que vous pouvez également modifier directement le fichier XML afin d'ajouter des destinations :

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" />

Vous disposez à présent de ce superbe graphique, mais vous ne l'utilisez pas vraiment pour la navigation.

Activités et navigation

Le composant de navigation est conforme aux directives de la section Principles of Navigation (Principes de navigation). Il y est notamment conseillé d'utiliser des activités comme points d'entrée pour votre application. Les activités contiennent également une navigation générale, comme la barre de navigation inférieure.

À titre de comparaison, les fragments sont les mises en page spécifiques à la destination.

Pour que cela fonctionne, vous devez modifier vos mises en page d'activité pour qu'elles contiennent un widget spécial, appelé NavHostFragment. Un NavHostFragment remplace différentes destinations de fragment lorsque vous parcourez le graphique de navigation.

Voici une mise en page simple autorisant une navigation semblable à l'illustration ci-dessus. Vous trouverez un exemple de ce code dans le fichier 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>

Remarques :

  • Il s'agit d'une mise en page pour une activité. Elle comprend la navigation générale, avec une barre de navigation inférieure et une barre d'outils.
  • android:name="androidx.navigation.fragment.NavHostFragment" et app:defaultNavHost="true" connectent le bouton "Retour" du système à NavHostFragment.
  • app:navGraph="@navigation/mobile_navigation" associe NavHostFragment à un graphique de navigation. Ce graphique de navigation indique toutes les destinations auxquelles l'utilisateur peut accéder, dans ce NavHostFragment.

Enfin, lorsqu'un utilisateur effectue une action telle qu'un clic sur un bouton, vous devez déclencher une commande de navigation. Une classe spéciale appelée NavController déclenche l'échange de fragments dans NavHostFragment.

// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)

Notez que vous devez indiquer un identifiant d'action ou de destination pour effectuer la navigation. Ces identifiants sont définis dans le code XML du graphique de navigation. Voici un exemple de transmission d'un identifiant de destination.

NavController est une classe particulièrement efficace, car lorsque vous appelez des méthodes telles que navigate() ou popBackStack(),, ces commandes sont converties en opérations de framework appropriées en fonction du type de la destination de navigation. Par exemple, lorsque vous appelez navigate() avec une destination d'activité, NavController appelle startActivity() pour vous.

Vous pouvez obtenir un objet NavController associé à votre widget NavHostFragment de plusieurs façons. Dans le langage Kotlin, il est recommandé d'utiliser l'une des fonctions d'extension suivantes, selon que vous appelez la commande de navigation à partir d'un fragment, d'une activité ou d'une vue :

C'est maintenant à votre tour d'utiliser la navigation à l'aide de NavController. Vous allez associer le bouton Navigate To Destination (Aller à la destination) pour accéder à la destination flow_step_one_dest (qui est une destination FlowStepFragment) :

1. Ouvrez HomeFragment.kt.

2. Associez le navigate_destination_button dans 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. Exécutez l'application, puis cliquez sur le bouton Navigate To Destination (Aller à la destination). Notez que ce bouton permet d'accéder à la destination flow_step_one_dest.

Le code de l'écouteur de clics se présente comme suit :

val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener(
        Navigation.createNavigateOnClickListener(R.id.flow_step_one_dest, null)
)

Comme vous pouvez le voir ci-dessous, la transition par défaut associée à chaque appel navigate() n'est pas très attrayante :

Dans l'écran d'accueil, l'utilisateur clique sur "Navigate to Destination" et accède à la première étape.

La transition par défaut, ainsi que d'autres attributs associés à l'appel, peuvent être remplacés en ajoutant un ensemble de NavOptions. NavOptions utilise un modèle Builder qui vous permet de ne définir que les options dont vous avez besoin. Il existe également un DSL ktx pour NavOptions. C'est celui que vous utiliserez.

Pour les transitions animées, vous pouvez définir des ressources d'animation XML dans le dossier de ressources anim, puis utiliser ces animations pour les transitions. Le code de l'application contient quelques exemples :

Ajouter une transition personnalisée

Mettez à jour le code de sorte que le bouton Navigate To Destination affiche une animation de transition personnalisée.

1. Ouvrez HomeFragment.kt.

2. Définissez une NavOptions et transmettez-la à l'appel de navigate() vers 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. Supprimez le code ajouté à l'étape 5, à condition qu'il soit toujours présent.

4. Vérifiez que le fragment glisse sur l'écran lorsque vous appuyez sur le bouton Navigate to Destination et disparaît de l'écran lorsque vous appuyez à nouveau sur ce bouton.

Actions

Le système de navigation vous permet également de naviguer par le biais d'actions. Comme indiqué précédemment, les lignes affichées dans le graphique de navigation sont des représentations visuelles des actions.

La navigation à l'aide d'actions présente les avantages suivants par rapport à la navigation par destination :

  • Vous pouvez visualiser les chemins de navigation via votre appli
  • Les actions peuvent contenir des attributs associés supplémentaires que vous pouvez définir, tels qu'une animation de transition, des valeurs d'arguments et un comportement de pile "Retour"
  • Vous pouvez utiliser le plug-in Safe Args pour la navigation (nous y reviendrons ultérieurement)

Voici la représentation visuelle et le code XML de l'action qui connecte flow_step_one_dest à 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>

Remarques :

  • Les actions sont imbriquées dans la destination ; il s'agit de la destination à partir de laquelle vous allez naviguer
  • L'action comprend un argument de destination faisant référence à flow_step_two_dest ; il s'agit de l'identifiant de votre destination de navigation
  • L'identifiant de l'action est "next_action"

Voici un autre exemple de l'action qui connecte flow_step_two_dest à 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>

Remarques :

  • Le même identifiant next_action est utilisé pour l'action qui connecte flow_step_two_dest à home_dest. L'identifiant next_action vous permet de naviguer à partir de flow_step_one_dest ou de flow_step_two_dest. Cet exemple illustre la manière dont les actions peuvent fournir un niveau d'abstraction et vous permettre d'accéder à une autre destination en fonction du contexte.
  • L'attribut popUpTo est utilisé. Cette action affiche des fragments de la pile "Retour" tant que vous n'avez pas atteint home_dest.

Le moment est venu d'associer le bouton Navigate with Action pour que l'action effectuée soit conforme à l'intitulé.

1. Ouvrez le fichier mobile_navigation.xml en mode Design.

2. Faites glisser une flèche de home_dest vers flow_step_one_dest :

3. Une fois la flèche d'action sélectionnée (en bleu), modifiez les propriétés de l'action pour obtenir le résultat suivant :

  • ID = next_action
  • Transition pour "Enter" = slide_in_right
  • Transition pour "Exit" = slide_out_left
  • Transitions pour "Pop Enter" = slide_in_left
  • Transitions pour "Pop Exit" = slide_out_right

4. Cliquez sur l'onglet Text.

Notez la nouvelle action next_action ajoutée sous la destination 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. Ouvrez HomeFragment.kt.

6. Ajoutez un écouteur de clics à navigate_action_button

HomeFragment.kt

 view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
        Navigation.createNavigateOnClickListener(R.id.next_action, null)
)

7. Vérifiez qu'il est désormais possible d'accéder à l'écran suivant en appuyant sur Navigate To Action.

Safe Args

Le composant de navigation dispose d'un plug-in Gradle, appelé Safe Args, qui génère des classes "Builder" et des classes d'objets simples pour un accès avec sûreté de typage aux arguments spécifiés pour les destinations et les actions.

Safe Args vous permet de vous débarrasser de code comme celui-ci lors de la transmission de valeurs entre des destinations :

val username = arguments?.getString("usernameKey")

Et de le remplacer par du code qui a généré des setters et des getters.

val username = args.username

Transmettre une valeur à l'aide de Safe Args

1. Ouvrez le fichier build.gradle du projet et observez le plug-in Safe Args :

build.gradle

dependencies {
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    //...
    }

2. Ouvrez le fichier app/build.gradle et observez le plug-in appliqué :

app/build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs.kotlin'

android {
   //...
}

3. Ouvrez mobile_navigation.xml, et observez comment les arguments sont définis dans la destination 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>

À l'aide de la balise <argument>, Safe Args génère une classe appelée FlowStepFragmentArgs.

Étant donné que le code XML comprend un argument appelé flowStepNumber, spécifié par android:name="flowStepNumber", la classe générée FlowStepFragmentArgs inclut une variable flowStepNumber avec des getters et des setters.

4. Ouvrez FlowStepFragment.kt.

5. Commentez la ligne de code affiché ci-dessous :

FlowStepFragment.kt

// Comment out this line
// val flowStepNumber = arguments?.getInt("flowStepNumber")

Ce code à l'ancienne n'utilise pas la sûreté du typage. Il est préférable d'utiliser Safe Args.

6. Mettez à jour FlowStepFragment de manière à utiliser la classe FlowStepFragmentArgs générée par le code. Cela vous permettra d'obtenir les arguments FlowStepFragment avec sûreté du typage :

FlowStepFragment.kt

val safeArgs: FlowStepFragmentArgs by navArgs()
val flowStepNumber = safeArgs.flowStepNumber

Classes Directions de Safe Args

Vous pouvez également utiliser Safe Args pour naviguer de manière sécurisée, en ajoutant ou non des arguments. Pour ce faire, utilisez les classes Directions générées.

Les classes Directions sont générées pour chaque destination distincte avec des actions. La classe Directions comprend des méthodes pour chaque action d'une destination.

Par exemple, l'écouteur de clics navigate_action_button du fragment HomeFragment.kt peut être remplacé par :

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

Les composants de navigation comprennent une classe NavigationUI et les extensions Kotlin navigation-ui-ktx. NavigationUI comporte des méthodes statiques qui associent des éléments de menu à des destinations de navigation. navigation-ui-ktx est un ensemble de fonctions d'extension qui font la même chose. Si NavigationUI trouve un élément de menu ayant le même identifiant qu'une destination sur le graphique actuel, il le configure pour qu'il pointe vers cette destination.

Utiliser NavigationUI avec un menu Options

Pour utiliser NavigationUI, la méthode la plus facile consiste à simplifier la configuration du menu d'options. NavigationUI simplifie, en particulier, la gestion du rappel onOptionsItemSelected.

1. Ouvrez MainActivity.kt.

Comme vous pouvez le constater, vous disposez déjà du code pour gonfler le menu overflow_menu en onCreateOptionsMenu.

2. Ouvrez res/menu/overflow_menu.xml.

3. Mettez à jour votre menu à développer afin d'y inclure settings_dest.

overflow_menu.xml

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:menuCategory="secondary"
    android:title="@string/settings" />

4. Ouvrez MainActivity.kt.

5. Faites en sorte que NavigationUI gère onOptionsItemSelected avec la méthode d'assistance onNavDestinationSelected. Si l'élément de menu n'est pas destiné à la navigation, utilisez super.onOptionsItemSelected.

MainActivity.kt

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
            || super.onOptionsItemSelected(item)
}

6. Exécutez votre application. Vous devriez normalement disposer d'un menu "ActionBar" opérationnel permettant d'accéder à SettingsFragment.

Utiliser NavigationUI pour configurer la barre de navigation inférieure

La barre de navigation inférieure est affichée, car le code contient déjà le code XML de mise en page permettant de l'implémenter. Cependant, elle ne permet d'accéder à aucune destination.

1. Ouvrez res/layout/navigation_activity/navigation_activity.xml (h470dp), puis cliquez sur l'onglet Text.

Vous remarquerez que le code XML de mise en page pour la barre de navigation inférieure est présent et fait référence à 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. Ouvrez res/menu/bottom_nav_menu.xml.

Notez qu'il existe deux éléments pour la barre de navigation inférieure et que leurs identifiants correspondent aux destinations du graphique de navigation :

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>

Faisons maintenant en sorte que la barre de navigation inférieure effectue une action à l'aide de NavigationUI.

3. Ouvrez MainActivity.kt.

4. Implémentez la méthode setupBottomNavMenu à l'aide de setupWithNavController(bottomNavigationView: BottomNavigationView, navController: NavController)

MainActivity.kt

private fun setupBottomNavMenu(navController: NavController) {
    val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
    bottomNav?.setupWithNavController(navController)
}

La barre de navigation inférieure est maintenant opérationnelle.

Utiliser NavigationUI pour configurer un panneau de navigation

Pour terminer, nous allons utiliser NavigationUI pour configurer la navigation latérale et le panneau de navigation, ce qui inclut la gestion de la barre d'action et une navigation correcte vers le haut. C'est le cas si votre écran est suffisamment grand ou s'il est trop court pour une barre de navigation inférieure.

Notez tout d'abord que le code XML de mise en page approprié figure déjà dans l'application.

1. Ouvrez navigation_activity.xml et navigation_activity.xml (w960dp).

Comme vous pouvez le voir, les deux mises en page contiennent un élément NavigationView qui est connecté à nav_drawer_menu. Dans la version pour tablette (w960dp), NavigationView est toujours à l'écran. Sur les appareils de plus petite taille, NavigationView est imbriqué dans un DrawerLayout.

Vous pouvez maintenant commencer à implémenter la navigation NavigationView.

2. Ouvrez MainActivity.kt.

3. Implémentez la méthode setupNavigationMenu à l'aide de setupWithNavController(navigationView: NavigationView, navController: NavController). Notez que cette version de la méthode utilise un élément NavigationView et non un élément BottomNavigationView.

MainActivity.kt

private fun setupNavigationMenu(navController: NavController) {
    val sideNavView = findViewById<NavigationView>(R.id.nav_view)
    sideNavView?.setupWithNavController(navController)
}

Le menu d'affichage de la navigation est maintenant affiché, mais il n'a aucune incidence sur la barre d'action.

Pour configurer ActionBar, vous devez créer une instance de AppBarConfiguration. L'objectif de AppBarConfiguration est de spécifier les options de configuration souhaitées pour les barres d'outils, les barres d'outils de réduction et les barres d'action. Les options de configuration indiquent si la barre doit gérer une mise en page de panneaux, ainsi que les destinations qui sont considérées comme étant de niveau supérieur.

Ces destinations de niveau supérieur sont les destinations racines de votre application. Aucun bouton "vers le haut" n'est affiché dans la barre d'application, mais l'icône de panneau est visible si la destination utilise une mise en page de panneaux.

4. Créez un objet AppBarConfiguration en transmettant un ensemble d'identifiants de destination de niveau supérieur et la mise en page de panneaux.

MainActivity.kt

val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
        setOf(R.id.home_dest, R.id.deeplink_dest),
        drawerLayout)

Maintenant que vous disposez d'une classe AppBarConfiguration, vous pouvez appeler NavigationUI.setupActionBarWithNavController pour :

  • afficher un titre dans la barre d'action en fonction du libellé de la destination ;
  • afficher le bouton "Vers le haut" lorsque vous n'êtes pas dans une destination de niveau supérieur ;
  • afficher une icône de panneau (icône du menu trois barres) lorsque vous êtes dans une destination de niveau supérieur.

5. Implémentez setupActionBarWithNavController.

MainActivity.kt

private fun setupActionBar(navController: NavController,
                           appBarConfig : AppBarConfiguration) {
    setupActionBarWithNavController(navController, appBarConfig)
}

Vous devez également faire en sorte que NavigationUI gère ce qui se produit lorsque vous appuyez sur le bouton "Vers le haut".

6. Remplacez onSupportNavigationUp et appelez NavigationUI.navigateUp, avec la même classe AppBarConfiguration.

MainActivity.kt

override fun onSupportNavigateUp(): Boolean {
    return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}

7. Exécutez votre code. Si vous ouvrez l'application en mode Écran partagé, un panneau de navigation opérationnel doit normalement être disponible. L'icône vers le haut et celle du panneau doivent s'afficher aux moments appropriés et fonctionner correctement.

Il est facile d'ajouter des destinations à un NavigationView. Une fois que le panneau de navigation permet de naviguer vers le haut ou vers l'arrière, il vous suffit d'ajouter le nouvel élément de menu.

8. Ouvrez menu/nav_drawer_menu.xml.

9. Ajoutez un élément de menu pour settings_dest.

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:title="@string/settings" />

Vos panneaux de navigation affichent désormais l'écran "Settings" (Paramètres) en tant que destination. Bravo !

Les composants de navigation sont également compatibles avec les liens profonds. Les liens profonds permettent d'accéder directement au cœur de la navigation de votre application, que ce soit depuis un lien URL ou un intent en attente à partir d'une notification.

Utiliser la bibliothèque de navigation pour gérer des liens profonds permet de s'assurer que les utilisateurs commencent au niveau de la destination appropriée avec la pile "Retour" adéquate provenant d'autres points d'entrée tels que des widgets d'application, des notifications ou des liens Web (qui seront décrits à l'étape suivante).

Le système de navigation fournit une classe NavDeepLinkBuilder pour construire un PendingIntent qui redirige l'utilisateur vers une destination spécifique.

Nous allons utiliser NavDeepLinkBuilder pour associer un widget d'application à une destination.

1. Ouvrez DeepLinkAppWidgetProvider.kt.

2. Ajoutez un PendingIntent créé avec 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)

Remarques :

  • setGraph inclut le graphique de navigation.
  • setDestination indique la destination du lien.
  • setArguments inclut tous les arguments que vous souhaitez transmettre à votre lien profond.

3. Ajoutez le widget de lien profond à votre écran d'accueil. Appuyez de manière prolongée sur l'écran d'accueil pour afficher l'option permettant d'ajouter un widget.

Appuyer de manière prolongée.

Faire défiler l'écran vers le bas pour rechercher le widget

Lorsque vous avez terminé, un widget de lien profond s'affiche.

4. Appuyez sur le widget et vérifiez que la destination Android s'ouvre avec l'argument approprié. Le libellé "From Widget" doit s'afficher en haut de l'écran, car il s'agit de l'argument que vous avez transmis à DeepLinkAppWidgetProvider.

5. Vérifiez que le bouton "Retour" permet d'accéder à la destination home_dest.

La pile "Retour" d'un lien profond est déterminée à l'aide du graphique de navigation que vous transmettez. Si l'activité explicite que vous avez choisie comporte une activité parente, celle-ci est également incluse.

La pile "Retour" est générée à l'aide des destinations spécifiées avec app:startDestination. Cette application ne comporte qu'une seule activité et un seul niveau de navigation. Par conséquent, la pile "Retour" vous redirige vers la destination home_dest.

Dans les scénarios de navigation plus complexes, des graphiques de navigation peuvent être imbriqués. L'élément app:startDestination à chaque niveau des graphiques imbriqués détermine la pile "Retour". Pour en savoir plus sur les liens profonds et les graphiques imbriqués, consultez la section Principles of Navigation (Principes de navigation).

Les liens profonds sont généralement utilisés pour permettre à un lien Web d'ouvrir une activité dans votre application. Habituellement, vous devez utiliser un filtre d'intent et associer une URL à l'activité que vous souhaitez ouvrir.

La bibliothèque de navigation rend cette opération extrêmement simple et vous permet de mapper directement les URL vers des destinations de votre graphique de navigation.

<deepLink> est un élément que vous pouvez ajouter à une destination dans votre graphique. Chaque élément <deepLink> comprend un seul attribut obligatoire : app:uri.

Outre la correspondance directe des URI, les fonctionnalités suivantes sont acceptées :

  • Les URI sans schéma sont censés utiliser les protocoles HTTP et HTTPS. Par exemple, www.example.com correspond à http://www.example.com et https://www.example.com.
  • Vous pouvez utiliser des espaces réservés sous la forme {placeholder_name} pour établir une correspondance avec un ou plusieurs caractères. La valeur "String" de l'espace réservé est disponible dans le groupe d'arguments qui possède une clé du même nom. Par exemple, http://www.example.com/users/{id} correspond à http://www.example.com/users/4.
  • Vous pouvez utiliser le caractère générique .* pour établir une correspondance avec zéro ou plusieurs caractères.
  • NavController gère automatiquement les intents ACTION_VIEW et recherche des liens profonds correspondants.

Au cours de cette étape, vous allez ajouter un lien profond vers www.example.com.

1. Ouvrez mobile_navigation.xml.

2. Ajoutez un élément <deepLink> à la destination 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. Ouvrez AndroidManifest.xml.

4. Ajoutez la balise nav-graph pour que filtre d'intent approprié soit généré.

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. Lancez votre application à l'aide d'un lien profond. Pour cela, vous pouvez procéder de deux façons :

  • Utilisez adb :
adb shell am start -a android.intent.action.VIEW -d "http://www.example.com/urlTest" 
  • Ouvrez l'appli Google et saisissez www.example.com/urlTest dans la barre de recherche pour afficher la fenêtre de désambiguïsation. Sélectionnez Navigation codelab (Atelier de programmation sur la navigation).

Ouvert à l'aide de la barre de recherche

(pas dans Chrome)

Boîte de dialogue de désambiguïsation

Quelle que soit la méthode choisie, le message "urlTest" doit s'afficher à l'écran. Il a été transmis au fragment à partir de l'URL.

Il y a un dernier élément dans l'application de l'atelier que vous pouvez encore tester, à savoir le bouton du panier.

Voici un récapitulatif des compétences que vous avez acquises au cours de cet atelier de programmation. Il n'y a pas de commentaires dans cette étape. Essayez de la réaliser en solitaire :

  1. Créer une classe de fragment
  2. Ajouter le fragment en tant que destination à votre graphique de navigation
  3. Faire en sorte que l'icône du panier ouvre votre nouvelle classe de fragment, en utilisant NavigationUI pour gérer le menu

Vous connaissez maintenant les concepts de base du composant de navigation. Les sujets suivants ont été traités au cours de cet atelier de programmation :

  • Structure du graphique de navigation
  • NavHostFragment et NavController
  • Comment accéder à des destinations spécifiques
  • Comment effectuer une navigation par action
  • Comment transmettre des arguments entre des destinations, y compris à l'aide du nouveau plug-in Safe Args
  • Navigation à l'aide de menus, de barres de navigation inférieure et de panneaux de navigation
  • Navigation via un lien profond


Vous pouvez poursuivre l'exploration avec cette application ou commencer à utiliser la navigation dans votre propre application.

Il reste encore beaucoup de choses à tester. En voici un aperçu :

  • Afficher des destinations de la pile "Retour" (ou toute manipulation de la pile "Retour")
  • Graphiques de navigation imbriqués
  • Navigation conditionnelle
  • Compatibilité avec les nouvelles destinations

Pour en savoir plus sur le composant de navigation, consultez la documentation. Si vous souhaitez en savoir plus sur les autres composants d'architecture, suivez les ateliers de programmation ci-dessous :