Progetta il tuo grafico di navigazione

Il componente Navigation utilizza un grafo di navigazione per gestire la navigazione dell'app. Il grafo di navigazione è una struttura di dati che contiene ogni destinazione all'interno della tua app e le connessioni tra di esse.

Tipi di destinazione

Esistono tre tipi generali di destinazioni: ospitate, di dialogo e di attività. La tabella che segue illustra questi tre tipi di destinazioni e le relative finalità.

Digitazione

Descrizione

Casi d'uso

In hosting

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

Schermate principali e di dettaglio.

Finestra di dialogo

Mostra i componenti dell'interfaccia utente in 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à

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

Serve come punto di uscita del grafico di navigazione che avvia una nuova attività Android gestita separatamente dal componente di navigazione.

Nello sviluppo Android moderno, un'app è costituita da una singola attività. Le destinazioni delle attività sono quindi ideali per interagire con attività di terze parti o nell'ambito della procedura di migrazione.

Questo documento contiene esempi di destinazioni ospitate, ovvero le destinazioni più comuni e fondamentali. Per informazioni sulle altre destinazioni, consulta le seguenti guide:

Framework

Sebbene in ogni caso si applichi lo stesso flusso di lavoro generale, la modalità esatta di creazione di un host e di un grafico di navigazione dipende dal framework dell'interfaccia utente utilizzato.

  • Componi:utilizza il composable NavHost. Aggiungi un NavGraph utilizzando il DSL Kotlin. Puoi creare il grafico in due modi:
    • Come parte di NavHost: costruisci il grafo di navigazione direttamente come parte dell'aggiunta del NavHost.
    • In modo programmatico: utilizza il metodo NavController.createGraph() per creare un NavGraph e passarlo direttamente al NavHost.
  • Fragment: quando utilizzi i frammenti con il framework UI delle visualizzazioni, utilizza un NavHostFragment come host. Esistono diversi modi per creare un grafo di navigazione:
    • In modo programmatico:utilizza il DSL Kotlin per creare un NavGraph e applicarlo direttamente al NavHostFragment.
      • La funzione createGraph() utilizzata con il DSL Kotlin sia per i frammenti sia per Compose è la stessa.
    • XML: scrivi l'host e il grafico di navigazione direttamente in XML.
    • Editor di Android Studio:utilizza l'editor GUI in Android Studio per creare e modificare il grafico come file di risorsa XML.

Scrivi

In Compose, utilizza un oggetto o una classe serializzabile per definire una route. Un percorso descrive come raggiungere una destinazione e contiene tutte le informazioni richieste dalla destinazione.

Utilizza l'annotazione @Serializable per creare automaticamente i metodi di serializzazione e deserializzazione necessari per i tipi di route. Questa annotazione è fornita dal plug-in Kotlin Serialization. Segui queste istruzioni per aggiungere questo plug-in.

Una volta definiti i percorsi, utilizza il composable NavHost per creare il gráfo 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 ciascuno dei due percorsi, Profile e FriendsList.
  2. La chiamata al composable NavHost passa un NavController e un percorso per la destinazione di partenza.
  3. La funzione lambda passata a NavHost chiama NavController.createGraph() e restituisce un NavGraph.
  4. Ogni percorso viene fornito come argomento di tipo a NavGraphBuilder.composable<T>(), che aggiunge la destinazione al NavGraph risultante.
  5. La funzione lambda passata a composable è ciò che NavHost mostra per quella destinazione.

Informazioni su lambda

Per comprendere meglio la funzione lambda che crea NavGraph, tieni presente che per creare lo stesso grafico dello snippet precedente, puoi creare NavGraph separatamente utilizzando NavController.createGraph() e passarlo direttamente a NavHost:

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

Passare gli argomenti

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

@Serializable
data class Profile(val name: String)

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

Per gli argomenti facoltativi, crea campi con valori null con un valore predefinito.

@Serializable
data class Profile(val nickname: String? = null)

Ottenere l'istanza della route

Puoi ottenere l'istanza del percorso 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) }
}

Tieni presente quanto segue in questo snippet:

  • 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>{}.
  • Il composable ProfileScreen assume il valore di profile.name per il proprio argomento name.
  • Di conseguenza, il valore "John Smith" viene trasmesso a ProfileScreen.

Esempio minimo

Un esempio completo di utilizzo combinato di NavController e NavHost:

@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, anziché passare NavController ai composabili, esponi un evento a NavController.NavHost In altre parole, i composabili devono avere un parametro di tipo () -> Unit a cui NavHost passa un lambda che chiama NavController.navigate().

Frammenti

Come descritto nelle sezioni precedenti, quando utilizzi i frammenti hai la possibilità di creare un grafo di navigazione a livello di programmazione utilizzando il DSL Kotlin, XML o l'editor Android Studio.

Le sezioni seguenti descrivono in dettaglio questi diversi approcci.

In modo programmatico

Il DSL Kotlin fornisce un modo programmatico per creare un grafo di navigazione con frammenti. In molti modi, è più pulito e moderno rispetto all'utilizzo di un file di risorse XML.

Considera l'esempio seguente, che implementa un grafo di navigazione a 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 al NavHostFragment.

Successivamente, la chiamata a NavController.createGraph() collega il grafico al NavController e di conseguenza anche al 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 del DSL in questo modo è molto simile al flusso di lavoro descritto nella sezione precedente su Composizione. Ad esempio, sia lì che qui, la funzione NavController.createGraph() genera NavGraph. Analogamente, mentre NavGraphBuilder.composable() aggiunge destinazioni composable al grafo, qui NavGraphBuilder.fragment() aggiunge una destinazione del frammento.

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

XML

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

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

Un'implementazione minima di un 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 grafo di navigazione all'host di navigazione. Di seguito è riportato un esempio di come 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>

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

Editor

Puoi gestire il grafo di navigazione della tua app utilizzando l'editor di navigazione in Android Studio. Si tratta essenzialmente di un'interfaccia utente grafica che puoi utilizzare per creare e modificare il tuo file XML NavigationFragment, come illustrato nella sezione precedente.

Per ulteriori informazioni, consulta Editor di navigazione.

Grafici nidificati

Puoi anche utilizzare grafici nidificati. Ciò comporta l'utilizzo di un grafo come destinazione di navigazione. Per ulteriori informazioni, consulta la sezione Grafici nidificati.

Per approfondire

Per altri concetti di navigazione di base, consulta le seguenti guide:

  • Panoramica: assicurati di leggere la panoramica generale del componente Navigation.
  • Destinazioni attività: esempi di come implementare destinazioni che indirizzano l'utente alle attività.
  • Destinazioni di dialogo: esempi di come creare destinazioni che indirizzano l'utente a una finestra di dialogo.
  • Andare a una destinazione: una guida dettagliata che spiega come muoversi da una destinazione all'altra.
  • Grafici nidificati: una guida approfondita su come nidificare un grafico di navigazione all'interno di un altro.