Verschachtelte Grafiken

Anmeldeabläufe, Assistenten oder andere Unterabläufe in Ihrer App werden in der Regel am besten als verschachtelte Navigationsdiagramme dargestellt. Durch das Einbetten in sich geschlossener Subnavigationsflüsse auf diese Weise ist der Hauptfluss der Benutzeroberfläche Ihrer App leichter zu verstehen und zu verwalten.

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

Beispiel

Der Navigationsgraph der obersten Ebene Ihrer App sollte mit dem anfä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 Navigationsdiagramm auf oberster Ebene.

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

Als Best Practice sollten Sie den match-Bildschirm als Startziel des Navigationsdiagramms der obersten Ebene festlegen und die Titel- und Registrierungsbildschirme in ein verschachteltes Diagramm verschieben, wie in Abbildung 1 dargestellt:

Abbildung 2: Der Navigationsgraph der obersten Ebene enthält jetzt einen verschachtelten Graphen.

Prüfe beim Start des Match-Bildschirms, ob ein registrierter Nutzer vorhanden ist. Wenn der Nutzer nicht registriert ist, leiten Sie ihn zum Registrierungsbildschirm weiter.

Weitere Informationen zu bedingten Navigationsszenarien finden Sie unter Bedingte Navigation.

Schreiben

Wenn Sie mit Compose einen verschachtelten Navigationsgraphen erstellen möchten, verwenden Sie die Funktion NavGraphBuilder.navigation(). Sie verwenden navigation() wie die Funktionen NavGraphBuilder.composable() und NavGraphBuilder.dialog(), wenn Sie einem Diagramm Ziele hinzufügen.

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

Sehen Sie sich an, wie das Diagramm in Abbildung 2 im folgenden Snippet mit Compose implementiert wird:

// 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 untergeordneten Ziel navigieren 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 jeder Bildschirm navigieren kann:

navController.navigate(route = Match)
.

XML

Wenn Sie XML verwenden, können Sie den Navigationseditor verwenden, um den verschachtelten Graphen zu 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 Move to Nested Graph > New Graph (In untergeordnetes Diagramm verschieben > Neues Diagramm) aus. Die Ziele sind in einem verschachtelten Diagramm enthalten. Abbildung 2 zeigt ein verschachteltes Diagramm im Navigationseditor:

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

    • Typ, der „Geschachteltes Diagramm“ enthält
    • ID, die eine vom System zugewiesene ID für das verschachtelte Diagramm enthält. Mit dieser ID wird im Code auf den verschachtelten Graphen verwiesen.
  4. Doppelklicken Sie auf das verschachtelte Diagramm, um die zugehörigen Ziele aufzurufen.

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

Eine weitere Möglichkeit, die Diagrammstruktur zu modularisieren, besteht darin, ein Diagramm mit einem <include>-Element im übergeordneten Navigationsdiagramm in ein anderes einzufügen. So kann das enthaltene Diagramm 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">

    <include app:graph="@navigation/included_graph" />

    <fragment
        android:id="@+id/fragment"
        android:name="com.example.myapplication.BlankFragment"
        android:label="Fragment in Root Graph"
        tools:layout="@layout/fragment_blank">
        <action
            android:id="@+id/action_fragment_to_second_graph"
            app:destination="@id/second_graph" />
    </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"
    android:id="@+id/second_graph"
    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>