Navigation Compose: cos'è, architettura e lavoro nello sviluppo

Autore: IT Sectr Pubblicato: 2026-06-29 Tempo di lettura: 8 min

Navigation Compose è una libreria Jetpack per la navigazione dichiarativa all'interno di applicazioni Android costruite con Jetpack Compose. Invece di FragmentManager o navigazione basata su Intent, Navigation Compose offre un grafo di rotte unico gestito tramite NavController e NavHost. Secondo Google I/O (2025), Navigation Compose è il metodo di navigazione raccomandato per le applicazioni Compose, utilizzato in oltre il 70% dei nuovi progetti. La libreria supporta il passaggio di argomenti tipizzati, collegamenti profondi, animazioni di transizione e l'integrazione con ViewModel tramite SavedStateHandle.

Punti chiave

  • Navigation Compose — una libreria Jetpack per la navigazione dichiarativa in Compose con un grafo di rotte unificato
  • NavController — il controller centrale che gestisce lo stack di navigazione e lo stato dello stack arretrato
  • NavHost — un contenitore che definisce il grafo di rotte tramite funzioni composable con route
  • Argomenti vengono passati tramite NavType e SavedStateHandle con supporto di parametri tipizzati
  • Collegamenti profondi — navigazione tramite URL esterni con analisi automatica degli argomenti dall'URI

Cos'è Navigation Compose?

Navigation Compose è una libreria della suite Jetpack che fornisce un framework di navigazione per applicazioni Compose. La libreria si basa sugli stessi principi del Componente di Navigazione per il sistema View, ma è adattata alla natura dichiarativa di Compose: invece di FragmentTransaction, vengono utilizzate funzioni composable e il grafo di navigazione viene costruito tramite Kotlin DSL.

La differenza principale tra Navigation Compose e la navigazione classica è l'assenza di FragmentManager. Ogni schermata è una funzione composable che viene renderizzata in NavHost quando la rotta corrisponde. Lo stack arretrato memorizza non un Fragment, ma un record con rotta, argomenti e stato. Questo semplifica l'architettura ed elimina i conflitti del ciclo di vita tipici della navigazione basata su Fragment.

Secondo Google (2025), Navigation Compose è passato da sperimentale a stabile e fa parte di Jetpack dalla versione 2.8.0. La libreria supporta Material3, navigazione type-safe (tramite Kotlin Serialization), grafi annidati e modularizzazione. L'unica limitazione è che la libreria non supporta lo stack arretrato multiplo per BottomNavigation senza configurazione manuale, sebbene Google stia lavorando su questo.

L'architettura di Navigation Compose ruota attorno a tre entità: NavController (gestione dello stack), NavHost (contenitore del grafo) e NavDestination (rotta individuale con composable). L'interazione tra di esse è dichiarativa: lo sviluppatore descrive le rotte e gli argomenti, e la libreria gestisce gli stati di caricamento, conservazione e ripristino.

NavController è l'elemento centrale di Navigation Compose, che gestisce lo stack di navigazione. Viene creato tramite rememberNavController() e passato a NavHost. NavController memorizza lo stack arretrato, il punto di ingresso corrente e supporta azioni differite (deeplink dopo l'inizializzazione del grafo).

kotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("profile/{userId}") { backStackEntry ->
            ProfileScreen(
                userId = backStackEntry.arguments?.getString("userId") ?: ""
            )
        }
    }
}

Metodi principali di NavController: navigate(route) — navigare verso una rotta, popBackStack() — tornare alla schermata precedente, navigateAndClear(route) — navigare e pulire lo stack. NavOptions specificano il comportamento: launchSingleTop previene duplicati, popUpTo pulisce lo stack fino alla rotta specificata, restoreState ripristina lo stato precedente.

Per accedere a NavController da funzioni composable profondamente annidate, utilizzare NavHostController tramite CompositionLocal. LocalNavController viene fornito in ScopedNavController all'interno di NavHost. Al di fuori di NavHost (ad esempio, in BottomNavigation), il controller viene passato tramite parametri o ViewModel.

NavHost è un contenitore composable che collega NavController al grafo di rotte. Ogni rotta viene dichiarata tramite composable(route, arguments, deepLinks), dove route è una stringa di rotta con segnaposto {param} opzionali. Quando la rotta corrente corrisponde, NavHost renderizza il blocco composable corrispondente.

Il grafo di rotte viene costruito gerarchicamente: i grafi possono essere annidati tramite navigation() per raggruppare le rotte all'interno di un modulo. I grafi annidati hanno il proprio startDestination e vengono combinati sotto un prefisso di rotta comune. Questo consente di organizzare un'architettura modulare dove ogni modulo di funzionalità registra il proprio sottografo.

kotlin
NavHost(
    navController = navController,
    startDestination = "main"
) {
    composable("main") { MainScreen(navController) }
    navigation(
        route = "auth",
        startDestination = "auth/login"
    ) {
        composable("auth/login") { LoginScreen(navController) }
        composable("auth/register") { RegisterScreen(navController) }
    }
}

NavHost gestisce automaticamente il pulsante Indietro di sistema (back press) tramite LocalBackDispatcher. In Material3 Scaffold, acquisisce per impostazione predefinita NavController per il corretto funzionamento di BottomNavigation. NavHost ricrea il composable quando la rotta cambia, ma preserva lo stato tramite rememberSaveable per i campi di input e lo scorrimento.

Passaggio di argomenti tra schermate

Navigation Compose supporta il passaggio di argomenti tipizzati tra schermate tramite parametri di rotta e NavType. I parametri vengono specificati nella rotta come {paramName} con il tipo indicato tramite arguments in composable(). NavType supporta String, Int, Long, Float, Boolean, Parcelable e Serializable.

Tipo di argomentoNavTypeEsempio di rotta
StringNavType.StringType"profile/{name}"
IntNavType.IntType"item/{id}"
BooleanNavType.BoolType"settings?enabled={flag}"
ParcelableNavType.ParcelableType"details/{item}"
FloatNavType.FloatType"map?lat={lat}&lng={lng}"

Gli argomenti vengono estratti da NavBackStackEntry tramite arguments?.getType(key). Per i parametri obbligatori utilizzare defaultValue, per quelli opzionali — nullable. Il supporto Parcelable funziona solo con Kotlin Parcelize o la libreria kotlinx.parcelize. Per oggetti complessi, si consiglia di passare un ID e caricare i dati tramite ViewModel, invece di serializzare l'intero oggetto.

Dalla versione Navigation 2.8.0, è stata introdotta la navigazione type-safe con Kotlin Serialization: le rotte vengono definite come classi di dati e gli argomenti come campi. Questo sostituisce le rotte stringa con oggetti tipizzati ed elimina gli errori nei nomi delle rotte. La migrazione richiede il plugin Kotlin Serialization e la dipendenza navigation-compose-typesafe.

kotlin
@Serializable
/* sealed class Route */
sealed class ProfileRoute(val route: String) {
    data object Home : ProfileRoute("home")
    data class Profile(val userId: String) : ProfileRoute("profile/{userId}")
}

I collegamenti profondi sono un meccanismo di navigazione che consente di aprire una schermata specifica dell'applicazione tramite URL o intent-filter. In Navigation Compose, i collegamenti profondi vengono configurati tramite il parametro deepLinks in composable() e vengono elaborati automaticamente quando l'URI corrisponde al modello.

Un collegamento profondo viene specificato come elenco UriPattern: "https://example.com/profile/{userId}". I parametri URI vengono mappati automaticamente agli argomenti della rotta. NavController elabora i collegamenti profondi all'avvio dell'applicazione (tramite intent) e durante il funzionamento (tramite collegamenti profondi impliciti). Per gestire i collegamenti profondi in sospeso, utilizzare handleDeepLink() in NavController dopo l'inizializzazione del grafo.

Secondo Google, i collegamenti profondi sono raccomandati per: notifiche push (Firebase Dynamic Links), verifica email, condivisione di contenuti e navigazione incrociata da collegamenti web. Per Android 12+, vengono utilizzati Digital Asset Links per verificare l'autorità del collegamento profondo. AndroidManifest.xml deve contenere un intent-filter con autoVerify="true" per aprire i collegamenti senza dialogo.

kotlin
composable(
    route = "profile/{userId}",
    arguments = listOf(navArgument("userId") { type = NavType.StringType }),
    deepLinks = listOf(
        navDeepLink { uriPattern = "https://example.com/profile/{userId}" }
    )
) { backStackEntry ->
    ProfileScreen(userId = backStackEntry.arguments?.getString("userId") ?: "")
}

Limitazioni dei collegamenti profondi in Navigation Compose: la libreria non supporta collegamenti profondi differiti — un collegamento profondo viene elaborato solo dopo che NavHost ha costruito completamente il grafo. Se un collegamento profondo arriva prima dell'inizializzazione del grafo, deve essere differito tramite intent?.data e elaborato in LaunchedEffect. Per Firebase Dynamic Links, utilizzare Firebase Dynamic Links SDK insieme a Navigation Compose.

Animazioni di transizione tra schermate

Navigation Compose supporta le animazioni di transizione tramite i parametri enterTransition, exitTransition, popEnterTransition e popExitTransition in composable(). Le animazioni sono implementate utilizzando l'API di animazione Compose: fadeIn, slideInHorizontally, expandIn e altre. Per impostazione predefinita, l'animazione è disattivata — le schermate vengono sostituite istantaneamente.

Scenari tipici di animazione: slideInHorizontally per la navigazione in avanti (la schermata entra da destra), slideOutHorizontally per il ritorno (la schermata esce a destra). Per BottomNavigation, l'animazione di dissolvenza senza scorrimento è più comunemente utilizzata. Le animazioni vengono impostate tramite NavHost e si applicano a tutti i composable a meno che non vengano specificate animazioni individuali.

kotlin
NavHost(
    navController = navController,
    startDestination = "home",
    enterTransition = { slideInHorizontally() + fadeIn() },
    exitTransition = { slideOutHorizontally() + fadeOut() },
    popEnterTransition = { fadeIn() },
    popExitTransition = { slideOutHorizontally() + fadeOut() }
) { /* composable */ }

Le animazioni possono essere sovrascritte per ogni composable individualmente passando parametri di animazione direttamente in composable(). È importante che le animazioni non entrino in conflitto con l'animazione di back press del sistema. Per la transizione di elementi condivisi, è necessaria la libreria accompanist-navigation-animation o un'implementazione personalizzata tramite Modifier.graphicsLayer. Secondo Android Developers (2025), l'80% delle applicazioni di produzione utilizza l'animazione di scorrimento orizzontale per la navigazione standard.

Domande frequenti

In cosa si differenzia Navigation Compose dal Componente di Navigazione per View?

Navigation Compose funziona senza Fragment, utilizzando funzioni composable e Kotlin DSL per il grafo. Il Componente di Navigazione (View) si basa su FragmentManager e grafi XML. La versione Compose è più semplice, più veloce e non ha cicli di vita di Fragment. Il Componente di Navigazione per View è adatto solo per applicazioni ibride.

Come passare un oggetto complesso tra schermate?

Si consiglia di passare l'ID dell'oggetto e caricare i dati tramite ViewModel con SavedStateHandle. Se l'oggetto è semplice, utilizzare Parcelable tramite kotlinx.parcelize. Passare oggetti grandi direttamente tramite argomenti (Bundle) è limitato a ~1 MB e può causare TransactionTooLargeException.

Navigation Compose supporta grafi annidati?

Sì, tramite la funzione navigation(route, startDestination) all'interno di NavHost. I grafi annidati hanno il proprio startDestination e vengono combinati sotto un prefisso di rotta comune. Ciò consente di organizzare un'architettura modulare con grafi isolati per ogni modulo di funzionalità.

Come gestire il pulsante Indietro di sistema in Navigation Compose?

NavController gestisce automaticamente la pressione del pulsante Indietro tramite BackHandler di Compose. Chiamare navController.popBackStack() quando viene premuto Indietro. Per una gestione personalizzata (conferma di uscita), utilizzare BackHandler(enabled = condition) { callback } prima di chiamare popBackStack().

Si può usare Navigation Compose con Jetpack Compose Multiplatform?

Attualmente, Navigation Compose non è supportato in Compose Multiplatform. Per la parte iOS dei progetti multipiattaforma, utilizzare Voyager o Decompose. Google sta lavorando al supporto KMP, ma non ci sono tempistiche di rilascio. Per progetti solo Android, Navigation Compose è l'unica opzione raccomandata.

Riepilogo

  • Navigation Compose — una libreria Jetpack per la navigazione dichiarativa in Compose, che funziona tramite un grafo di rotte e NavController
  • NavController gestisce lo stack arretrato e fornisce i metodi navigate, popBackStack per la navigazione
  • NavHost collega il controller al grafo tramite composable(), supportando grafi annidati per architettura modulare
  • Argomenti vengono passati tramite NavType con supporto per String, Int, Parcelable e navigazione type-safe con Kotlin Serialization
  • Collegamenti profondi vengono configurati tramite navDeepLink con UriPattern per navigazione esterna da URL e notifiche push
  • Animazione delle transizioni viene impostata tramite enterTransition, exitTransition utilizzando l'API di animazione Compose
  • La libreria non supporta KMP e lo stack arretrato multiplo per BottomNavigation senza configurazione aggiuntiva

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche