Navigation Compose: qué es, arquitectura y trabajo en el desarrollo

Autor: IT Sectr Publicado: 2026-06-29 Tiempo de lectura: 8 min

Navigation Compose es una biblioteca Jetpack para navegación declarativa dentro de aplicaciones Android construidas con Jetpack Compose. En lugar de FragmentManager o navegación basada en Intent, Navigation Compose ofrece un único grafo de rutas gestionado a través de NavController y NavHost. Según Google I/O (2025), Navigation Compose es el método de navegación recomendado para aplicaciones Compose, utilizado en más del 70% de los nuevos proyectos. La biblioteca admite el paso de argumentos tipificados, enlaces profundos, animaciones de transición e integración con ViewModel a través de SavedStateHandle.

Puntos clave

  • Navigation Compose — una biblioteca Jetpack para navegación declarativa en Compose con un grafo de rutas unificado
  • NavController — el controlador central que gestiona la pila de navegación y el estado de la pila de retroceso
  • NavHost — un contenedor que define el grafo de rutas mediante funciones composables con ruta
  • Argumentos se pasan a través de NavType y SavedStateHandle con soporte de parámetros tipificados
  • Enlaces profundos — navegación a través de URL externas con análisis automático de argumentos desde URI

¿Qué es Navigation Compose?

Navigation Compose es una biblioteca del conjunto Jetpack que proporciona un marco de navegación para aplicaciones Compose. La biblioteca se basa en los mismos principios que el Componente de Navegación para el sistema View, pero está adaptada a la naturaleza declarativa de Compose: en lugar de FragmentTransaction se utilizan funciones composables, y el grafo de navegación se construye mediante Kotlin DSL.

La diferencia clave entre Navigation Compose y la navegación clásica es la ausencia de FragmentManager. Cada pantalla es una función composable que se renderiza en NavHost cuando la ruta coincide. La pila de retroceso almacena no un Fragment, sino un registro con ruta, argumentos y estado. Esto simplifica la arquitectura y elimina los conflictos de ciclo de vida típicos de la navegación basada en Fragment.

Según Google (2025), Navigation Compose ha pasado de experimental a estable y forma parte de Jetpack desde la versión 2.8.0. La biblioteca admite Material3, navegación con seguridad de tipos (a través de Kotlin Serialization), grafos anidados y modularización. La única limitación es que la biblioteca no admite la pila de retroceso múltiple para BottomNavigation sin configuración manual, aunque Google está trabajando en ello.

La arquitectura de Navigation Compose gira en torno a tres entidades: NavController (gestión de la pila), NavHost (contenedor del grafo) y NavDestination (ruta individual con composable). La interacción entre ellas es declarativa: el desarrollador describe las rutas y los argumentos, y la biblioteca maneja los estados de carga, conservación y restauración.

NavController es el elemento central de Navigation Compose, que gestiona la pila de navegación. Se crea mediante rememberNavController() y se pasa a NavHost. NavController almacena la pila de retroceso, el punto de entrada actual y admite acciones diferidas (deeplink después de la inicialización 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") ?: ""
            )
        }
    }
}

Métodos principales de NavController: navigate(route) — navegar a una ruta, popBackStack() — volver a la pantalla anterior, navigateAndClear(route) — navegar y limpiar la pila. NavOptions especifican el comportamiento: launchSingleTop evita duplicados, popUpTo limpia la pila hasta la ruta especificada, restoreState restaura el estado anterior.

Para acceder a NavController desde funciones composables profundamente anidadas, use NavHostController a través de CompositionLocal. LocalNavController se proporciona en ScopedNavController dentro de NavHost. Fuera de NavHost (por ejemplo, en BottomNavigation), el controlador se pasa a través de parámetros o ViewModel.

NavHost es un contenedor composable que vincula NavController con el grafo de rutas. Cada ruta se declara mediante composable(route, arguments, deepLinks), donde route es una cadena de ruta con marcadores de posición {param} opcionales. Cuando la ruta actual coincide, NavHost renderiza el bloque composable correspondiente.

El grafo de rutas se construye jerárquicamente: los grafos se pueden anidar mediante navigation() para agrupar rutas dentro de un módulo. Los grafos anidados tienen su propio startDestination y se combinan bajo un prefijo de ruta común. Esto permite organizar una arquitectura modular donde cada módulo de funcionalidad registra su propio subgrafo.

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 maneja automáticamente el botón de retroceso del sistema (back press) a través de LocalBackDispatcher. En Material3 Scaffold, por defecto recoge NavController para el correcto funcionamiento de BottomNavigation. NavHost recrea el composable cuando la ruta cambia, pero conserva el estado mediante rememberSaveable para campos de entrada y desplazamiento.

Paso de argumentos entre pantallas

Navigation Compose admite el paso de argumentos tipificados entre pantallas a través de parámetros de ruta y NavType. Los parámetros se especifican en la ruta como {paramName} con el tipo indicado mediante arguments en composable(). NavType admite String, Int, Long, Float, Boolean, Parcelable y Serializable.

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

Los argumentos se extraen de NavBackStackEntry a través de arguments?.getType(key). Para parámetros obligatorios use defaultValue, para opcionales — nullable. El soporte de Parcelable funciona solo con Kotlin Parcelize o la biblioteca kotlinx.parcelize. Para objetos complejos, se recomienda pasar un ID y cargar datos a través de ViewModel, en lugar de serializar el objeto completo.

Desde Navigation 2.8.0, se introdujo la navegación con seguridad de tipos con Kotlin Serialization: las rutas se definen como clases de datos y los argumentos como campos. Esto reemplaza las rutas de cadena con objetos tipificados y elimina errores en los nombres de las rutas. La migración requiere el plugin de Kotlin Serialization y la dependencia 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}")
}

Enlaces profundos es un mecanismo de navegación que permite abrir una pantalla específica de la aplicación a través de una URL o intent-filter. En Navigation Compose, los enlaces profundos se configuran mediante el parámetro deepLinks en composable() y se procesan automáticamente cuando la URI coincide con el patrón.

Un enlace profundo se especifica como una lista de UriPattern: "https://example.com/profile/{userId}". Los parámetros de URI se asignan automáticamente a los argumentos de la ruta. NavController procesa los enlaces profundos al iniciar la aplicación (a través de intent) y durante la operación (a través de enlaces profundos implícitos). Para manejar enlaces profundos pendientes, use handleDeepLink() en NavController después de la inicialización del grafo.

Según Google, se recomiendan enlaces profundos para: notificaciones push (Firebase Dynamic Links), verificación de correo electrónico, compartir contenido y navegación transversal desde enlaces web. Para Android 12+, se utilizan Digital Asset Links para verificar la autoridad del enlace profundo. AndroidManifest.xml debe contener un intent-filter con autoVerify="true" para abrir enlaces sin diálogo.

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") ?: "")
}

Limitaciones de los enlaces profundos en Navigation Compose: la biblioteca no admite enlaces profundos diferidos — un enlace profundo se procesa solo después de que NavHost haya construido completamente el grafo. Si un enlace profundo llega antes de la inicialización del grafo, debe diferirse mediante intent?.data y procesarse en LaunchedEffect. Para Firebase Dynamic Links, use el SDK de Firebase Dynamic Links junto con Navigation Compose.

Animaciones de transición entre pantallas

Navigation Compose admite animaciones de transición mediante los parámetros enterTransition, exitTransition, popEnterTransition y popExitTransition en composable(). Las animaciones se implementan usando la API de animación de Compose: fadeIn, slideInHorizontally, expandIn y otras. Por defecto, la animación está desactivada — las pantallas se reemplazan instantáneamente.

Escenarios típicos de animación: slideInHorizontally para navegación hacia adelante (la pantalla entra desde la derecha), slideOutHorizontally para retroceder (la pantalla sale hacia la derecha). Para BottomNavigation, se usa más comúnmente la animación de desvanecimiento sin deslizamiento. Las animaciones se configuran a través de NavHost y se aplican a todos los composables a menos que se especifiquen individuales.

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

Las animaciones se pueden anular para cada composable individualmente pasando parámetros de animación directamente en composable(). Es importante que las animaciones no entren en conflicto con la animación de retroceso del sistema. Para la transición de elementos compartidos, se requiere la biblioteca accompanist-navigation-animation o una implementación personalizada mediante Modifier.graphicsLayer. Según Android Developers (2025), el 80% de las aplicaciones de producción utilizan animación de deslizamiento horizontal para la navegación estándar.

Preguntas frecuentes

¿En qué se diferencia Navigation Compose del Componente de Navegación para View?

Navigation Compose funciona sin Fragment, utilizando funciones composables y Kotlin DSL para el grafo. El Componente de Navegación (View) se basa en FragmentManager y grafos XML. La versión Compose es más simple, más rápida y no tiene ciclos de vida de Fragment. El Componente de Navegación para View solo es adecuado para aplicaciones híbridas.

¿Cómo pasar un objeto complejo entre pantallas?

Se recomienda pasar el ID del objeto y cargar los datos a través de ViewModel con SavedStateHandle. Si el objeto es simple, use Parcelable mediante kotlinx.parcelize. Pasar objetos grandes directamente a través de argumentos (Bundle) está limitado a ~1 MB y puede causar TransactionTooLargeException.

¿Navigation Compose admite grafos anidados?

Sí, mediante la función navigation(route, startDestination) dentro de NavHost. Los grafos anidados tienen su propio startDestination y se combinan bajo un prefijo de ruta común. Esto permite organizar una arquitectura modular con grafos aislados para cada módulo de funcionalidad.

¿Cómo manejar el botón de retroceso del sistema en Navigation Compose?

NavController maneja automáticamente la pulsación de retroceso a través de BackHandler de Compose. Llame a navController.popBackStack() cuando se presione Atrás. Para manejo personalizado (confirmación de salida), use BackHandler(enabled = condition) { callback } antes de llamar a popBackStack().

¿Se puede usar Navigation Compose con Jetpack Compose Multiplatform?

Actualmente, Navigation Compose no es compatible con Compose Multiplatform. Para la parte iOS de proyectos multiplataforma, use Voyager o Decompose. Google está trabajando en soporte para KMP, pero no hay fecha de lanzamiento. Para proyectos solo Android, Navigation Compose es la única opción recomendada.

Resumen

  • Navigation Compose — una biblioteca Jetpack para navegación declarativa en Compose, que funciona a través de un grafo de rutas y NavController
  • NavController gestiona la pila de retroceso y proporciona métodos navigate, popBackStack para la navegación
  • NavHost vincula el controlador al grafo mediante composable(), admitiendo grafos anidados para arquitectura modular
  • Argumentos se pasan a través de NavType con soporte para String, Int, Parcelable y navegación con seguridad de tipos con Kotlin Serialization
  • Enlaces profundos se configuran mediante navDeepLink con UriPattern para navegación externa desde URL y notificaciones push
  • Animación de transiciones se configura mediante enterTransition, exitTransition usando la API de animación de Compose
  • La biblioteca no admite KMP ni la pila de retroceso múltiple para BottomNavigation sin configuración adicional

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también