Grafici nidificati

I flussi di accesso, le procedure guidate o altri sottoflussi all'interno dell'app in genere sono rappresentati al meglio come grafici di navigazione nidificati. Se nidifichi in questo modo i flussi di navigazione secondaria autonomi, il flusso principale dell'UI dell'app è più facile da comprendere e gestire.

Inoltre, i grafici nidificati sono riutilizzabili. Forniscono anche un livello di incapsulamento: le destinazioni al di fuori del grafico nidificato non hanno accesso diretto a nessuna delle destinazioni all'interno del grafico nidificato. Invece, devono navigate() al grafico nidificato stesso, dove la logica interna può cambiare senza influire sul resto del grafico.

Esempio

Il grafico di navigazione di primo livello dell'app deve iniziare con la destinazione iniziale che l'utente vede quando avvia l'app e deve includere le destinazioni che vede mentre si sposta nell'app.

Figura 1. Un grafico di navigazione di primo livello.

Utilizzando come esempio il grafico di navigazione di primo livello della Figura 1, supponiamo che tu voglia richiedere all'utente di visualizzare le schermate title_screen e register solo al primo avvio dell'app. In seguito, le informazioni dell'utente vengono archiviate e, nei lanci successivi dell'app, dovresti portarlo direttamente alla schermata match.

Come best practice, imposta la schermata match come destinazione di avvio del grafico di navigazione di primo livello e sposta le schermate del titolo e di registrazione in un grafico nidificato, come mostrato nella Figura 1:

Figura 2. Il grafico di navigazione di primo livello ora contiene un grafico nidificato.

Quando viene avviata la schermata di corrispondenza, controlla se è presente un utente registrato. Se l'utente non è registrato, portalo alla schermata di registrazione.

Per ulteriori informazioni sugli scenari di navigazione condizionale, consulta Navigazione condizionale.

Scrivi

Per creare un grafico di navigazione nidificato utilizzando Compose, utilizza la NavGraphBuilder.navigation() funzione. Quando aggiungi destinazioni a un grafico, utilizzi navigation() come NavGraphBuilder.composable() e NavGraphBuilder.dialog() funzioni.

La differenza principale è che navigation crea un grafico nidificato anziché una nuova destinazione. Poi, chiama composable() e dialog() all'interno della lambda di navigation() per aggiungere destinazioni al grafico nidificato.

Considera come il seguente snippet implementa il grafico nella Figura 2 utilizzando 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 }
                   }
               }
           )
       }
   }
}

Per passare direttamente a una destinazione nidificata, utilizza un tipo di route come faresti per qualsiasi altra destinazione. Questo perché le route sono un concetto globale utilizzato per identificare le destinazioni a cui qualsiasi schermata può passare:

navController.navigate(route = Match)

XML

Quando utilizzi XML, puoi utilizzare l'editor di navigazione per creare il grafico nidificato. Per farlo, segui questi passaggi:

  1. Nell'editor di navigazione, tieni premuto il tasto Maiusc e fai clic sulle destinazioni che vuoi includere nel grafico nidificato.
  2. Fai clic con il tasto destro del mouse per aprire il menu contestuale e seleziona Sposta nel grafico nidificato > Nuovo grafico. Le destinazioni sono racchiuse in un grafico nidificato. La Figura 2 mostra un grafico nidificato nell'editor di navigazione:

    Figura 2. Grafico nidificato nell'editor di navigazione
  3. Fai clic sul grafico nidificato. Nel riquadro Attributi vengono visualizzati i seguenti attributi:

    • Tipo, che contiene "Grafico nidificato"
    • ID, che contiene un ID assegnato dal sistema per il grafico nidificato. Questo ID viene utilizzato per fare riferimento al grafico nidificato dal codice.
  4. Fai doppio clic sul grafico nidificato per visualizzarne le destinazioni.

  5. Fai clic sulla scheda Testo per passare alla visualizzazione XML. Al grafico è stato aggiunto un grafico di navigazione nidificato. Questo grafico di navigazione ha i propri elementi navigation, nonché il proprio ID e un attributo startDestination che punta alla prima destinazione del grafico nidificato:

    <?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. Nel codice, passa l'ID risorsa dell'azione che collega il grafico principale al grafico nidificato:

Kotlin

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

Java

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. Nella scheda Progettazione, torna al grafico principale facendo clic su Radice.

Fai riferimento ad altri grafici di navigazione con include

Un altro modo per modularizzare la struttura del grafico è includere un grafico all'interno di un altro utilizzando un elemento <include> nel grafico di navigazione principale. In questo modo, il grafico incluso può essere definito in un modulo o in un progetto separato, il che massimizza la riusabilità.

Il seguente snippet mostra come puoi utilizzare <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">

    <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>