Anmeldeabläufe, Assistenten oder andere untergeordnete Abläufe innerhalb Ihrer Anwendung werden normalerweise am besten als verschachtelte Navigationsgrafiken dargestellt. Wenn du eigenständige Subnavigationsabläufe auf diese Weise verschachtelst, lässt sich der Hauptablauf der UI deiner App leichter verstehen und verwalten.
Außerdem sind verschachtelte Grafiken wiederverwendbar. Sie bieten außerdem eine Kapselungsebene: Ziele außerhalb der verschachtelten Grafik haben keinen direkten Zugriff auf eines der Ziele innerhalb der verschachtelten Grafik. Stattdessen sollten sie mit navigate()
an die verschachtelte Grafik selbst übergeben werden, sodass sich die interne Logik ändern kann, ohne den Rest der Grafik zu beeinträchtigen.
Beispiel
Die Navigationsgrafik auf der obersten Ebene Ihrer App sollte mit dem anfänglichen Ziel beginnen, das der Nutzer beim Starten der App sieht. Außerdem sollte es die Ziele enthalten, die der Nutzer während der Navigation in der App sieht.
Nehmen wir als Beispiel das Navigationsdiagramm der obersten Ebene aus Abbildung 1. Angenommen, der Nutzer soll die Bildschirme title_screen und register nur dann sehen können, wenn die App zum ersten Mal gestartet wird. Danach werden die Nutzerinformationen gespeichert. Bei nachfolgenden Starts der App sollten Sie den Nutzer direkt zum Match-Bildschirm weiterleiten.
Als Best Practice wird empfohlen, den Übereinstimmungsbildschirm als Startziel der Navigationsgrafik auf oberster Ebene festzulegen und die Titel- und Registrierungsbildschirme in eine verschachtelte Grafik zu verschieben, wie in Abbildung 1 dargestellt:
Prüfen Sie auf dem Bildschirm für die Zuordnung, ob ein Nutzer registriert ist. Wenn der Nutzer nicht registriert ist, rufe den Registrierungsbildschirm auf.
Weitere Informationen zu Szenarien der bedingten Navigation finden Sie unter Bedingte Navigation.
Schreiben
Verwenden Sie die Funktion NavGraphBuilder.navigation()
, um mit Compose ein verschachteltes Navigationsdiagramm zu erstellen. Sie verwenden navigation()
auf dieselbe Weise wie die Funktionen NavGraphBuilder.composable()
und NavGraphBuilder.dialog()
, um einem Diagramm Ziele hinzuzufügen.
Der Hauptunterschied besteht darin, dass navigation
anstelle eines neuen Ziels eine verschachtelte Grafik erstellt. Anschließend rufen Sie composable
und dialog
im Lambda von navigation
auf, um dem verschachtelten Diagramm Ziele hinzuzufügen.
Im folgenden Snippet wird das Diagramm in Abbildung 2 mithilfe von Composer implementiert:
NavHost(navController, startDestination = "title_screen") {
composable("title_screen") {
TitleScreen(
onPlayClicked = { navController.navigate("register") },
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable("register") {
RegisterScreen(
onSignUpComplete = { navController.navigate("gameInProgress") }
)
}
navigation(startDestination = "match", route = "gameInProgress") {
composable("match") {
MatchScreen(
onStartGame = { navController.navigate("in_game") }
)
}
composable("in_game") {
InGameScreen(
onGameWin = { navController.navigate("results_winner") },
onGameLose = { navController.navigate("game_over") }
)
}
composable("results_winner") {
ResultsWinnerScreen(
onNextMatchClicked = {
navController.navigate("match") {
popUpTo("match") { inclusive = true }
}
},
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable("game_over") {
GameOverScreen(
onTryAgainClicked = {
navController.navigate("match") {
popUpTo("match") { inclusive = true }
}
}
)
}
}
}
Wenn Sie direkt zu einem verschachtelten Ziel navigieren möchten, verwenden Sie das route
wie zu jedem anderen Ziel. Dies liegt daran, dass Routen ein globales Konzept sind, zu dem jeder Bildschirm aufrufen kann:
navController.navigate("match")
Erweiterungsfunktionen
Sie können einem Diagramm mithilfe einer Erweiterungsfunktion in NavGraphBuilder
Ziele hinzufügen. Sie können diese Erweiterungsfunktionen zusammen mit den vordefinierten Erweiterungsmethoden navigation
, composable
und dialog
verwenden.
Sie können beispielsweise eine Erweiterungsfunktion verwenden, um die verschachtelte Grafik hinzuzufügen, die im vorherigen Abschnitt gezeigt wurde:
fun NavGraphBuilder.addNestedGraph(navController: NavController) {
navigation(startDestination = "match", route = "gameInProgress") {
composable("match") {
MatchScreen(
onStartGame = { navController.navigate("in_game") }
)
}
composable("in_game") {
InGameScreen(
onGameWin = { navController.navigate("results_winner") },
onGameLose = { navController.navigate("game_over") }
)
}
composable("results_winner") {
ResultsWinnerScreen(
onNextMatchClicked = { navController.navigate("match") },
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable("game_over") {
GameOverScreen(
onTryAgainClicked = { navController.navigate("match") }
)
}
}
}
Sie können diese Funktion dann in der Lambda-Funktion aufrufen, die Sie an NavHost
übergeben, anstatt die Navigation inline aufzurufen. Das folgende Beispiel veranschaulicht dies:
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(navController, startDestination = "title_screen") {
composable("title_screen") {
TitleScreen(
onPlayClicked = { navController.navigate("register") },
onLeaderboardsClicked = { /* Navigate to leaderboards */ }
)
}
composable("register") {
RegisterScreen(
onSignUpComplete = { navController.navigate("gameInProgress") }
)
}
// Add the nested graph using the extension function
addNestedGraph(navController)
}
}
XML
Bei Verwendung von XML können Sie mit dem Navigations-Editor Ihre verschachtelte Grafik erstellen. Gehen Sie dazu folgendermaßen vor:
- Halten Sie im Navigationseditor die Umschalttaste gedrückt und klicken Sie auf die Ziele, die in der verschachtelten Grafik enthalten sein sollen.
Klicken Sie mit der rechten Maustaste, um das Kontextmenü zu öffnen, und wählen Sie In verschachtelte Grafik verschieben > Neue Grafik aus. Die Ziele sind in einer verschachtelten Grafik eingeschlossen. Abbildung 2 zeigt ein verschachteltes Diagramm im Navigationseditor:
Klicken Sie auf die verschachtelte Grafik. Die folgenden Attribute werden im Bereich Attribute angezeigt:
- Typ, der „Verschachtelte Grafik“ enthält
- ID, die eine vom System zugewiesene ID für die verschachtelte Grafik enthält. Diese ID wird verwendet, um aus Ihrem Code auf die verschachtelte Grafik zu verweisen.
Doppelklicken Sie auf die verschachtelte Grafik, um ihre Ziele anzuzeigen.
Klicken Sie auf den Tab Text, um zur XML-Ansicht zu wechseln. Der Grafik wurde eine verschachtelte Navigationsgrafik hinzugefügt. Diese Navigationsgrafik hat eigene
navigation
-Elemente sowie eine eigene ID und einstartDestination
-Attribut, das auf das erste Ziel in der verschachtelten Grafik verweist:<?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>
Übergeben Sie in Ihrem Code die Ressourcen-ID der Aktion, die die Stammgrafik mit der verschachtelten Grafik verbindet:
Kotlin
view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
Java
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
Kehren Sie auf dem Tab Design zur Stammgrafik zurück, indem Sie auf Root klicken.
Mit „Einschließen“ auf andere Navigationsdiagramme verweisen
Eine weitere Möglichkeit zur Modularisierung der Diagrammstruktur besteht darin, ein Diagramm in ein anderes zu einschließen, indem Sie im übergeordneten Navigationsdiagramm ein <include>
-Element verwenden. Dadurch kann die enthaltene Grafik insgesamt in einem separaten Modul oder Projekt definiert werden, was die Wiederverwendbarkeit maximiert.
Das folgende Snippet zeigt, wie Sie <include>
verwenden können:
<!-- (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>
Weitere Informationen
Weitere Informationen zur Navigation finden Sie in den folgenden Ressourcen.