Verschachtelte Grafiken

Anmeldeabläufe, Assistenten oder andere Teilabläufe in Ihrer App werden in der Regel am besten als verschachtelte Navigationsgrafiken dargestellt. Wenn Sie auf diese Weise eigenständige Navigationsabläufe verschachteln, ist der Hauptablauf der Benutzeroberfläche Ihrer App leichter zu verstehen und zu verwalten.

Außerdem können verschachtelte Grafiken wiederverwendet werden. Außerdem bieten sie eine gewisse Kapselung: Ziele außerhalb des verschachtelten Graphen haben keinen direkten Zugriff auf die Ziele innerhalb des verschachtelten Graphen. Stattdessen sollten sie navigate() auf das verschachtelte Diagramm selbst anwenden, da sich die interne Logik ändern kann, ohne den Rest des Diagramms zu beeinflussen.

Verwendungsbeispiele

Das Navigationsdiagramm der obersten Ebene Ihrer App sollte mit dem ursprünglichen Ziel beginnen, das der Nutzer beim Starten der App sieht, und die Ziele enthalten, die er beim Navigieren in Ihrer App sieht.

Abbildung 1: Ein Navigationsgraph auf oberster Ebene.

Angenommen, Sie möchten, dass die Bildschirme title_screen und register nur beim ersten Start der App angezeigt werden. Anschließend werden die Nutzerinformationen gespeichert. Bei nachfolgenden Starts der App sollten Sie die Nutzer direkt zum Bildschirm Match weiterleiten.

Als Best Practice sollten Sie den Bildschirm Match als Startziel des Navigationsdiagramms der obersten Ebene festlegen und die Bildschirme „Titel“ und „Registrieren“ in ein verschachteltes Diagramm verschieben, wie in Abbildung 1 dargestellt:

Abbildung 2: Das Navigationsdiagramm der obersten Ebene enthält jetzt ein verschachteltes Diagramm.

Prüfen Sie, ob auf dem Abgleichsbildschirm ein registrierter Nutzer angezeigt wird. Wenn der Nutzer nicht registriert ist, rufe den Registrierungsbildschirm auf.

Weitere Informationen zu Szenarien für die bedingte Navigation finden Sie unter Bedingte Navigation.

Schreiben

Verwenden Sie die Funktion NavGraphBuilder.navigation(), um mit Compose ein verschachteltes Navigationsdiagramm zu erstellen. Sie verwenden navigation() genau wie die Funktionen NavGraphBuilder.composable() und NavGraphBuilder.dialog(), wenn Sie einer Grafik Ziele hinzufügen.

Der Hauptunterschied besteht darin, dass mit navigation ein verschachteltes Diagramm statt eines neuen Ziels erstellt wird. Anschließend rufen Sie composable() und dialog() innerhalb des Lambda-Codes von navigation() auf, um dem verschachtelten Graphen Ziele hinzuzufügen.

Im folgenden Snippet wird die Grafik in Abbildung 2 mit Compose implementiert:

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

Wenn Sie direkt zu einem verschachtelten Ziel wechseln möchten, verwenden Sie einen Routentyp wie bei jedem anderen Ziel. Das liegt daran, dass Routen ein globales Konzept sind, mit dem Ziele identifiziert werden, zu denen von jedem Bildschirm aus navigiert werden kann:

navController.navigate(route = Match)
.

XML

Wenn Sie XML verwenden, können Sie das verschachtelte Diagramm mit dem Navigationseditor erstellen. Gehen Sie dazu so vor:

  1. Halten Sie im Navigationseditor die Umschalttaste gedrückt und klicken Sie auf die Ziele, die Sie in den verschachtelten Graphen aufnehmen möchten.
  2. Klicken Sie mit der rechten Maustaste, um das Kontextmenü zu öffnen, und wählen Sie In verschachtelten Graphen verschieben > Neuer Graph aus. Die Ziele sind in einem verschachtelten Diagramm enthalten. Abbildung 2 zeigt ein verschachteltes Diagramm im Navigationseditor:

    Abbildung 2. Verschachtelte Grafik im Navigationseditor
  3. Klicken Sie auf das verschachtelte Diagramm. Die folgenden Attribute werden im Bereich Attribute angezeigt:

    • Typ, der „Verschachtelter Graph“ enthält
    • ID: Enthält eine systemzugewiesene ID für den verschachtelten Graphen. Diese ID wird verwendet, um in Ihrem Code auf die verschachtelte Grafik zu verweisen.
  4. Klicken Sie doppelt auf das verschachtelte Diagramm, um die Ziele zu sehen.

  5. Klicken Sie auf den Tab Text, um zur XML-Ansicht zu wechseln. Dem Diagramm wurde ein verschachteltes Navigationsdiagramm hinzugefügt. Dieses Navigationsdiagramm hat eigene navigation-Elemente sowie eine eigene ID und ein startDestination-Attribut, das auf das erste Ziel im verschachtelten Diagramm 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 den Stammgraphen mit dem verschachtelten Graphen verbindet:

Kotlin

view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)

Java

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. Kehren Sie auf dem Tab Design zum Stammdiagramm zurück, indem Sie auf Stamm klicken.

Mit „include“ auf andere Navigationsgrafiken verweisen

Eine weitere Möglichkeit, Ihre Diagrammstruktur zu modularisieren, besteht darin, ein Diagramm in ein anderes einzufügen. Verwenden Sie dazu ein <include>-Element im übergeordneten Navigationsdiagramm. So kann der enthaltene Graph 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 zusätzlichen Ressourcen.

Codelabs

Videos