Progetta il tuo grafico di navigazione

Il componente Navigazione utilizza un grafico di navigazione per gestire la navigazione nell'app. Il grafico di navigazione è una struttura di dati che contiene ogni destinazione all'interno dell'app e le connessioni tra le due.

Tipi di destinazione

Esistono tre tipi generali di destinazioni: ospitate, finestre di dialogo e attività. La seguente tabella descrive questi tre tipi di destinazione e i relativi scopi.

Tipo

Descrizione

casi d'uso

Ospitato

riempie l'intero host di navigazione. In altre parole, le dimensioni di una destinazione ospitata corrispondono a quelle dell'host di navigazione e le destinazioni precedenti non sono visibili.

Schermate principali e di dettaglio.

Finestra di dialogo

Presenta i componenti dell'interfaccia utente di overlay. Questa UI non è legata alla posizione dell'host di navigazione o alle sue dimensioni. Le destinazioni precedenti sono visibili sotto la destinazione.

Avvisi, selezioni, moduli.

Attività

Rappresentano schermate o funzionalità uniche all'interno dell'app.

Fungere da punto di uscita per il grafico di navigazione che avvia una nuova attività Android gestita separatamente dal componente di navigazione.

Nello sviluppo di Android moderno, un'app è composta da una singola attività. Pertanto, le destinazioni delle attività sono utilizzate al meglio quando si interagisce con attività di terze parti o nell'ambito del processo di migrazione.

Questo documento contiene esempi di destinazioni ospitate, che sono le destinazioni più comuni e fondamentali. Consulta le seguenti guide per informazioni sulle altre destinazioni:

Framework

Sebbene in tutti i casi venga applicato lo stesso flusso di lavoro generale, l'esatta creazione di un host di navigazione e di un grafico dipende dal framework dell'interfaccia utente utilizzato.

  • Scrivi:utilizza il componibile NavHost. Aggiungi un elemento NavGraph utilizzando Kotlin DSL. Puoi creare il grafico in due modi:
    • Come parte di NavHost: crea il grafico di navigazione direttamente come parte dell'aggiunta di NavHost.
    • In modo programmatico: usa il metodo NavController.createGraph() per creare un NavGraph e passarlo direttamente al NavHost.
  • Frammenti: se utilizzi frammenti con il framework dell'interfaccia utente delle viste, utilizza NavHostFragment come host. Esistono diversi modi per creare un grafico di navigazione:
    • In modo programmatico: usa il Kotlin DSL per creare un NavGraph e applicarlo direttamente a NavHostFragment.
      • La funzione createGraph() utilizzata con il DSL di Kotlin sia per i frammenti sia per Compose è la stessa.
    • XML: scrivi l'host di navigazione e il grafico direttamente in XML.
    • Editor di Android Studio: utilizza l'editor GUI in Android Studio per creare e modificare il grafico come un file di risorse XML.

Scrittura

In Compose, utilizza una classe o un oggetto serializzabile per definire una route. Un percorso descrive come raggiungere una destinazione e contiene tutte le informazioni necessarie per la destinazione. Dopo aver definito i percorsi, utilizza l'elemento componibile NavHost per creare il grafico di navigazione. Considera l'esempio seguente:

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. Un oggetto serializzabile rappresenta ciascuna delle due route, Profile e FriendsList.
  2. La chiamata all'elemento componibile NavHost passa un NavController e una route per la destinazione di partenza.
  3. La lambda trasmessa a NavHost alla fine chiama NavController.createGraph() e restituisce NavGraph.
  4. Ogni route viene fornita come argomento di tipo a NavGraphBuilder.composable<T>(), che aggiunge la destinazione al NavGraph risultante.
  5. La lambda passata a composable è ciò che mostra la NavHost per quella destinazione.

Comprendere la funzione lambda

Per comprendere meglio il lambda che crea NavGraph, tieni presente che, per creare lo stesso grafico dello snippet precedente, potresti creare l'elemento NavGraph separatamente utilizzando NavController.createGraph() e trasferirlo direttamente a NavHost:

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

Passa argomenti

Se devi passare dati a una destinazione, definisci la route con una classe che abbia parametri. Ad esempio, la route Profile è una classe di dati con un parametro name.

@Serializable
data class Profile(val name: String)

Ogni volta che devi passare argomenti a quella destinazione, devi creare un'istanza della classe di route, passando gli argomenti al costruttore di classe.

Ottieni istanza di route

Puoi ottenere l'istanza di route con NavBackStackEntry.toRoute() o SavedStateHandle.toRoute(). Quando crei una destinazione utilizzando composable(), NavBackStackEntry è disponibile come parametro.

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

In questo snippet tieni presente quanto segue:

  • La route Profile specifica la destinazione di partenza nel grafico di navigazione, con "John Smith" come argomento per name.
  • La destinazione stessa è il blocco composable<Profile>{}.
  • L'elemento componibile ProfileScreen prende il valore di profile.name per il proprio argomento name.
  • Di conseguenza, il valore "John Smith" passa a ProfileScreen.

Esempio minimo

Esempio completo di NavController e NavHost che funzionano insieme:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

Come dimostra lo snippet, invece di passare il valore NavController ai componibili, esponi un evento a NavHost. In altre parole, i tuoi componibili devono avere un parametro di tipo () -> Unit per il quale NavHost passa una funzione lambda che chiama NavController.navigate().

Frammenti

Come descritto nelle sezioni precedenti, quando utilizzi i frammenti hai la possibilità di creare un grafico di navigazione in modo programmatico utilizzando Kotlin DSL, XML o l'editor di Android Studio.

Le sezioni seguenti descrivono nel dettaglio questi diversi approcci.

In modo programmatico

Kotlin DSL offre un modo programmatico per creare un grafico di navigazione con frammenti. Questo metodo è più ordinato e moderno che utilizzare un file di risorse XML.

Considera l'esempio riportato di seguito, che implementa un grafico di navigazione su due schermate.

Innanzitutto è necessario creare NavHostFragment, che non deve includere un elemento app:navGraph:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

Quindi, passa il id del NavHostFragment a NavController.findNavController. In questo modo, il NavController viene associato a NavHostFragment.

La chiamata a NavController.createGraph() collega il grafico a NavController e di conseguenza anche a NavHostFragment:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

L'utilizzo di DSL in questo modo è molto simile al flusso di lavoro descritto nella precedente sezione su Scrivi. Ad esempio, sia qui che in questo caso, la funzione NavController.createGraph() genera NavGraph. Allo stesso modo, mentre NavGraphBuilder.composable() aggiunge destinazioni componibili al grafico, qui NavGraphBuilder.fragment() aggiunge una destinazione del frammento.

Per ulteriori informazioni su come utilizzare Kotlin DSL, consulta Creare un grafico con il NavGraphBuilder DSL.

XML

Puoi scrivere il codice XML direttamente tu. L'esempio seguente rispecchia ed è equivalente all'esempio su due schermate della sezione precedente.

Per prima cosa, crea un NavHostFragment. che funge da host di navigazione contenente il grafico di navigazione effettivo.

Un'implementazione minima di NavHostFragment:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

NavHostFragment contiene l'attributo app:navGraph. Utilizza questo attributo per collegare il grafico di navigazione all'host di navigazione. Di seguito è riportato un esempio di come potresti implementare il grafico:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

Puoi utilizzare le azioni per definire le connessioni tra destinazioni diverse. In questo esempio, il frammento profile contiene un'azione che accede a friendslist. Per ulteriori informazioni, consulta Utilizzare azioni e frammenti di navigazione.

Editor

Puoi gestire il grafico di navigazione della tua app utilizzando l'Editor di navigazione in Android Studio. Si tratta essenzialmente di una GUI che puoi utilizzare per creare e modificare il tuo XML di NavigationFragment, come descritto nella sezione precedente.

Per ulteriori informazioni, consulta Editor di navigazione.

Grafici nidificati

Puoi anche utilizzare grafici nidificati. Ciò comporta l'uso di un grafico come destinazione della navigazione. Per ulteriori informazioni, vedi Grafici nidificati.

Per approfondire

Per i concetti di navigazione più importanti, consulta le seguenti guide: