Verschachtelte Grafiken

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.

Abbildung 1: Ein Navigationsdiagramm der obersten Ebene.

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:

Abbildung 2: Die Navigationsgrafik der obersten Ebene enthält jetzt eine verschachtelte Grafik.

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:

  1. Halten Sie im Navigationseditor die Umschalttaste gedrückt und klicken Sie auf die Ziele, die in der verschachtelten Grafik enthalten sein sollen.
  2. 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:

    Abbildung 2. Verschachteltes Diagramm im Navigationseditor
  3. 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.
  4. Doppelklicken Sie auf die verschachtelte Grafik, um ihre Ziele anzuzeigen.

  5. 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 ein startDestination-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>
    
  6. Ü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);
    
  7. 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.

Produktproben

Codelabs

Videos