Les flux de connexion, les assistants ou d'autres sous-flux dans votre application sont généralement représentés par des graphiques de navigation imbriqués. En imbriquant ainsi les flux de sous-navigation autonomes, le flux principal de l'UI de votre application est plus facile à comprendre et à gérer.
De plus, les graphiques imbriqués sont réutilisables. Ils fournissent également un niveau d'encapsulation. En effet, les destinations situées en dehors du graphique imbriqué n'ont pas un accès direct aux destinations du graphique imbriqué. À la place, elles doivent naviguer (navigate()
) jusqu'au graphique imbriqué lui-même, où la logique interne peut changer sans affecter le reste du graphique.
Exemple
Le graphique de navigation de premier niveau de votre application doit commencer par la destination initiale que l'utilisateur voit lorsqu'il lance l'application et doit inclure les destinations qu'il voit lorsqu'il se déplace dans votre application.
En utilisant le graphique de navigation de premier niveau de la figure 1 comme exemple, imaginons que vous souhaitiez que l'utilisateur ne voie les écrans title_screen (écran titre) et register (inscription) que lorsque l'application est lancée pour la première fois. Par la suite, les informations utilisateur sont stockées et, lors des lancements suivants de l'application, l'utilisateur est amené directement à l'écran match (correspondance).
En guise de bonne pratique, il est recommandé de définir l'écran match (correspondance) comme destination de départ du graphique de navigation de premier niveau, puis de déplacer l'écran titre et l'écran d'inscription dans un graphique imbriqué, comme illustré dans la figure 1:
Lorsque l'écran de correspondance se lance, vérifiez si un utilisateur est enregistré. Si l'utilisateur n'est pas enregistré, redirigez-le vers l'écran d'enregistrement.
Pour en savoir plus sur les scénarios de navigation conditionnelle, consultez la page Navigation conditionnelle.
Compose
Pour créer un graphique de navigation imbriqué à l'aide de Compose, utilisez la fonction NavGraphBuilder.navigation()
. Vous utilisez navigation()
tout comme les fonctions NavGraphBuilder.composable()
et NavGraphBuilder.dialog()
lorsque vous ajoutez des destinations à un graphique.
La principale différence est que navigation
crée un graphique imbriqué plutôt qu'une nouvelle destination. Vous appelez ensuite composable()
et dialog()
dans le lambda de navigation()
pour ajouter des destinations au graphique imbriqué.
Examinons comment l'extrait suivant implémente le graphique de la figure 2 à l'aide de Compose :
// Routes
@Serializable object Title
@Serializable object Register
// Route for nested graph
@Serializable object Game
// Routes inside nested graph
@Serializable object Match
@Serializable object InGame
@Serializable object ResultsWinner
@Serializable object GameOver
NavHost(navController, startDestination = Title) {
composable<Title> {
TitleScreen(
onPlayClicked = { navController.navigate(route = Register) },
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable<Register> {
RegisterScreen(
onSignUpComplete = { navController.navigate(route = Game) }
)
}
navigation<Game>(startDestination = Match) {
composable<Match> {
MatchScreen(
onStartGame = { navController.navigate(route = InGame) }
)
}
composable<InGame> {
InGameScreen(
onGameWin = { navController.navigate(route = ResultsWinner) },
onGameLose = { navController.navigate(route = GameOver) }
)
}
composable<ResultsWinner> {
ResultsWinnerScreen(
onNextMatchClicked = {
navController.navigate(route = Match) {
popUpTo(route = Match) { inclusive = true }
}
},
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable<GameOver> {
GameOverScreen(
onTryAgainClicked = {
navController.navigate(route = Match) {
popUpTo(route = Match) { inclusive = true }
}
}
)
}
}
}
Pour accéder directement à une destination imbriquée, utilisez un type de route comme vous le feriez pour toute autre destination. En effet, les routes sont un concept global utilisé pour identifier les destinations auxquelles n'importe quel écran peut naviguer:
navController.navigate(route = Match)
XML
Lorsque vous utilisez le format XML, vous pouvez utiliser l'éditeur de navigation pour créer votre graphique imbriqué. Pour cela, procédez comme suit :
- Dans l'éditeur de navigation, appuyez de manière prolongée sur la touche Maj, puis cliquez sur les destinations que vous souhaitez inclure dans le graphique imbriqué.
Effectuez un clic droit pour ouvrir le menu contextuel, puis sélectionnez Move to Nested Graph > New Graph (Déplacer vers un graphique imbriqué > Nouveau graphique). Les destinations sont incluses dans un graphique imbriqué. La figure 2 montre un graphique imbriqué dans l'éditeur de navigation :
Cliquez sur le graphique imbriqué. Les attributs suivants apparaissent dans le panneau Attributes (Attributs) :
- Type, qui contient "Nested Graph" (Graphique imbriqué)
- ID, qui contient un ID attribué par le système pour le graphique imbriqué Cet ID permet de référencer le graphique imbriqué de votre code.
Double-cliquez sur le graphique imbriqué pour afficher ses destinations.
Cliquez sur l'onglet Text (Texte) pour passer à la vue XML. Un graphique de navigation imbriqué y a été ajouté. Ce graphique de navigation possède ses propres éléments
navigation
, ainsi que son propre ID et un attributstartDestination
qui pointe vers la première destination du graphique imbriqué :<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" app:startDestination="@id/mainFragment"> <fragment android:id="@+id/mainFragment" android:name="com.example.cashdog.cashdog.MainFragment" android:label="fragment_main" tools:layout="@layout/fragment_main" > <action android:id="@+id/action_mainFragment_to_sendMoneyGraph" app:destination="@id/sendMoneyGraph" /> <action android:id="@+id/action_mainFragment_to_viewBalanceFragment" app:destination="@id/viewBalanceFragment" /> </fragment> <fragment android:id="@+id/viewBalanceFragment" android:name="com.example.cashdog.cashdog.ViewBalanceFragment" android:label="fragment_view_balance" tools:layout="@layout/fragment_view_balance" /> <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient"> <fragment android:id="@+id/chooseRecipient" android:name="com.example.cashdog.cashdog.ChooseRecipient" android:label="fragment_choose_recipient" tools:layout="@layout/fragment_choose_recipient"> <action android:id="@+id/action_chooseRecipient_to_chooseAmountFragment" app:destination="@id/chooseAmountFragment" /> </fragment> <fragment android:id="@+id/chooseAmountFragment" android:name="com.example.cashdog.cashdog.ChooseAmountFragment" android:label="fragment_choose_amount" tools:layout="@layout/fragment_choose_amount" /> </navigation> </navigation>
Dans votre code, transmettez l'ID de ressource de l'action qui connecte le graphique racine au graphique imbriqué :
Kotlin
view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
Java
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
- Revenez dans l'onglet Design (Conception), puis accédez de nouveau au graphique racine en cliquant sur Root (Racine).
Référencer d'autres graphiques de navigation avec un élément "include"
Vous pouvez également modulariser la structure de votre graphique en incluant un graphique dans un autre à l'aide d'un élément <include>
dans le graphique de navigation parent. Le graphique inclus peut ainsi être défini dans un module ou un projet distinct, ce qui optimise sa réutilisation.
L'extrait suivant montre comment utiliser <include>
:
<!-- (root) nav_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<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"
android:id="@+id/nav_graph"
app:startDestination="@id/fragment">
<strong><include app:graph="@navigation/included_graph" /></strong>
<fragment
android:id="@+id/fragment"
android:name="com.example.myapplication.BlankFragment"
android:label="Fragment in Root Graph"
tools:layout="@layout/fragment_blank">
<strong><action
android:id="@+id/action_fragment_to_second_graph"
app:destination="@id/second_graph" /></strong>
</fragment>
...
</navigation>
<!-- included_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<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"
<strong>android:id="@+id/second_graph"</strong>
app:startDestination="@id/includedStart">
<fragment
android:id="@+id/includedStart"
android:name="com.example.myapplication.IncludedStart"
android:label="fragment_included_start"
tools:layout="@layout/fragment_included_start" />
</navigation>
Ressources supplémentaires
Pour en savoir plus sur la navigation, consultez les ressources supplémentaires suivantes.