Raggiungere una destinazione

Il componente Navigation fornisce un modo semplice e generico per navigare verso una destinazione. Questa interfaccia supporta una serie di contesti e framework UI. Ad esempio, puoi utilizzare il componente Navigation con Compose, visualizzazioni, fragment, attività e persino framework UI personalizzati.

Questa guida descrive come utilizzare il componente Navigation per navigare verso una destinazione in vari contesti.

Utilizzare un NavController

Il tipo di chiave principale che utilizzi per spostarti tra le destinazioni è il NavController. Per saperne di più sulla classe stessa e su come creare un'istanza, consulta Creare un controller di navigazione. Questa guida spiega come utilizzarlo.

Indipendentemente dal framework UI che utilizzi, esiste una singola funzione che puoi utilizzare per navigare verso una destinazione: NavController.navigate().

Sono disponibili molti overload per navigate(). L'overload che devi scegliere corrisponde al tuo contesto esatto. Ad esempio, devi utilizzare un overload quando navighi verso un componibile e un altro quando navighi verso una visualizzazione.

Le sezioni seguenti descrivono alcuni degli overload navigate() principali che puoi utilizzare.

Navigare verso un componibile

Per navigare verso un componibile, devi utilizzare NavController.navigate<T>. Con questo overload, navigate() accetta un singolo argomento route per il quale passi un tipo. Funge da chiave per una destinazione.

@Serializable
object FriendsList

navController.navigate(route = FriendsList)

Per navigare verso un componibile nel grafico di navigazione, definisci prima il tuo NavGraph in modo che ogni destinazione corrisponda a un tipo. Per i componibili, puoi farlo con la funzione composable().

Esponi gli eventi dai tuoi componibili

Quando una funzione componibile deve navigare verso una nuova schermata, non devi passargli un riferimento a NavController in modo che possa chiamare direttamente navigate(). In base ai principi del flusso di dati unidirezionale (UDF), il componibile deve invece esporre un evento gestito da NavController.

Più direttamente, il componibile deve avere un parametro di tipo () -> Unit. Quando aggiungi destinazioni a NavHost con la composable() funzione, passa al componibile una chiamata a NavController.navigate().

Per un esempio, consulta la seguente sottosezione.

Esempio

Per dimostrare le sezioni precedenti, osserva questi punti nel seguente snippet:

  1. Ogni destinazione nel grafico viene creata utilizzando una route, ovvero un oggetto o una classe serializzabile che descrive i dati richiesti da quella destinazione.
  2. Il componibile MyAppNavHost contiene l'istanza NavController.
  3. Di conseguenza, le chiamate a navigate() devono essere eseguite lì e non in un componibile inferiore come ProfileScreen.
  4. ProfileScreen contiene un pulsante che consente all'utente di navigare verso FriendsList quando viene fatto clic. Tuttavia, non chiama navigate() stesso.
  5. Il pulsante chiama invece una funzione esposta come parametro onNavigateToFriends.
  6. Quando MyAppNavHost aggiunge ProfileScreen al grafico di navigazione, per onNavigateToFriends passa un lambda che chiama navigate(route = FriendsList).
  7. In questo modo, quando l'utente preme il pulsante ProfileScreen, naviga correttamente verso FriendsListScreen.
@Serializable
object Profile
@Serializable
object FriendsList

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = Profile
    ) {
        composable<Profile> {
            ProfileScreen(
                onNavigateToFriends = { navController.navigate(route = FriendsList) },
                /*...*/
            )
        }
        composable<FriendsList> { FriendsListScreen(/*...*/) }
    }
}

@Composable
fun ProfileScreen(
    onNavigateToFriends: () -> Unit,
    /*...*/
) {
    /*...*/
    Button(onClick = onNavigateToFriends) {
        Text(text = "See friends list")
    }
}

Navigare utilizzando l'ID intero

Per navigare verso una destinazione utilizzando un ID intero, chiama l'navigate(int) overload. Accetta l'ID risorsa di un'azione o di una destinazione. Il seguente snippet di codice mostra come utilizzare questo overload per navigare verso ViewTransactionsFragment:

Kotlin

viewTransactionsButton.setOnClickListener { view ->
  view.findNavController().navigate(R.id.viewTransactionsAction)
}

Java

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
      Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
  }
});

Quando navighi utilizzando gli ID, devi utilizzare le azioni, se possibile. Le azioni forniscono informazioni aggiuntive nel grafico di navigazione, mostrando visivamente come le destinazioni si connettono tra loro.

Navigare da Compose in un'app basata su fragment

Se utilizzi Jetpack Compose all'interno di un'architettura di navigazione basata su fragment (ad esempio, in un'app mista di visualizzazioni e Compose), non puoi utilizzare le route di Compose con sicurezza dei tipi per navigare direttamente. Devi invece utilizzare gli ID interi (azioni) definiti nel grafico di navigazione XML.

Per modificare le destinazioni dal codice Compose, esponi un evento (lambda) dal componibile:

@Composable
fun MyScreen(onNavigateToProfile: () -> Unit) {
    Button(onClick = { onNavigateToProfile() }) {
        Text("Go to Profile")
    }
}

Nel fragment, collega Compose e il componente di navigazione basato su fragment chiamando NavController del fragment quando viene attivato l'evento:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    return ComposeView(requireContext()).apply {
        setContent {
            MyScreen(onNavigateToProfile = { findNavController().navigate(R.id.nav_profile) })
        }
    }
}

Questo approccio mantiene i componibili riutilizzabili e testabili, poiché non dipendono direttamente da NavController del fragment.

Navigare utilizzando NavDeepLinkRequest

Per navigare verso una destinazione di deep link implicito, utilizza l'overload navigate(NavDeepLinkRequest). Lo snippet seguente fornisce un'implementazione di questo metodo:

Kotlin

val request = NavDeepLinkRequest.Builder
  .fromUri("android-app://androidx.navigation.app/profile".toUri())
  .build()
findNavController().navigate(request)

Java

NavDeepLinkRequest request = NavDeepLinkRequest.Builder
  .fromUri(Uri.parse("android-app://androidx.navigation.app/profile"))
  .build()
NavHostFragment.findNavController(this).navigate(request)

A differenza della navigazione tramite ID azione o destinazione, puoi navigare verso qualsiasi deep link nel grafico, indipendentemente dal fatto che la destinazione sia visibile o meno. Puoi navigare verso una destinazione nel grafico corrente o in un grafico completamente diverso.

Azioni e tipi MIME

Oltre a Uri, NavDeepLinkRequest supporta anche i deep link con azioni e tipi MIME. Per aggiungere un'azione alla richiesta, utilizza fromAction() o setAction(). Per aggiungere un tipo MIME a una richiesta, utilizza fromMimeType() o setMimeType().

Affinché un NavDeepLinkRequest corrisponda correttamente a una destinazione di deep link implicito, l'URI, l'azione e il tipo MIME devono corrispondere a NavDeepLink nella destinazione. Gli URI devono corrispondere al pattern, le azioni devono essere una corrispondenza esatta e i tipi MIME devono essere correlati. Ad esempio, image/jpg corrisponde a image/\*.

Altri contesti

Questo documento spiega come utilizzare NavController.navigate() nei casi d'uso più comuni. Tuttavia, la funzione ha una serie di overload che puoi utilizzare in contesti diversi e in combinazione con qualsiasi framework UI. Per maggiori dettagli su questi overload, consulta la documentazione di riferimento.

Per approfondire

Per saperne di più, consulta le pagine seguenti: