NavHost — qué es, construcción del grafo y rutas en Jetpack Compose

Autor: IT Sectr Publicado: 2026-06-30 Tiempo de lectura: 7 min

NavHost es un contenedor composable que sirve como punto de entrada para el grafo de navegación en Jetpack Compose. Vincula un NavController con un conjunto de rutas y renderiza la pantalla actual según el estado de la pila de retroceso. Según Android Developers (2025), NavHost es un componente obligatorio para cualquier aplicación Compose con navegación. Dentro de NavHost se registran rutas composable con argumentos opcionales, deep links y animaciones. Cada ruta es una función composable normal que recibe un NavBackStackEntry con datos de transición. NavHost maneja automáticamente el botón de retroceso, la conservación del estado y la restauración en la reconfiguración.

Puntos Clave

  • NavHost — un contenedor composable que vincula NavController con un grafo de rutas y renderiza la pantalla actual
  • composable() — una función para registrar una ruta con ruta, argumentos, deep links y animaciones de transición
  • startDestination — la ruta inicial que se abre al crear NavHost
  • Argumentos se definen mediante navArgument con NavType para la transferencia de datos tipados entre pantallas
  • Animación se configura global o individualmente mediante los parámetros enterTransition, exitTransition

¿Qué es NavHost en Jetpack Compose?

NavHost es una función composable que proporciona un contenedor para mostrar la pantalla de navegación actual. NavHost recibe un NavController, startDestination y un grafo de rutas construido mediante Kotlin DSL. Cuando la ruta actual cambia, NavHost cambia el composable mostrado con la animación especificada.

NavHost funciona como un conmutador de pantallas: rastrea el NavBackStackEntry actual desde NavController y renderiza el bloque composable correspondiente. Cada pantalla es una función composable independiente que recibe un NavBackStackEntry con argumentos de ruta. Todas las pantallas existen en un único árbol de composición, pero NavHost muestra solo una a la vez, ocultando las demás mediante animación.

A diferencia de FragmentManager, NavHost no crea un Fragment para cada pantalla. Todo el ciclo de vida se gestiona mediante CompositionLifecycle — las funciones composable no tienen onStart/onResume, por lo que se usan LaunchedEffect y DisposableEffect para efectos secundarios. NavHost se suscribe automáticamente a NavController y recompone la UI cuando cambia la ruta.

Según Google, NavHost es una API estable desde Navigation 2.4.0. A partir de 2.8.0, NavHost soporta navegación Type-Safe mediante Kotlin Serialization, reemplazando rutas de cadena con clases de datos. NavHost también admite grafos anidados, lo que permite una organización modular de la navegación.

NavHost se crea con dos parámetros obligatorios: navController (una instancia de NavHostController) y startDestination (la cadena de ruta de la primera pantalla). El tercer parámetro es un bloque constructor donde se registran todas las rutas mediante composable(), navigation() y dialog().

kotlin
@Composable
fun AppNavHost(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") { HomeScreen(navController) }
        composable("settings") { SettingsScreen(navController) }
    }
}

startDestination es la ruta que se abre cuando se inicia NavHost por primera vez. Si la pila de retroceso está vacía, NavHost añade automáticamente startDestination a la pila. En la reconfiguración (rotación de pantalla), NavHost restaura la última ruta desde savedState, no startDestination.

Para BottomNavigation, startDestination es una de las rutas del panel inferior. Las rutas restantes del panel se añaden como entradas composable separadas. NavHost debe colocarse dentro de Scaffold.content — donde se muestra el contenido principal de la aplicación. NavHost ocupa toda la altura disponible menos TopAppBar y BottomNavigation.

Registro de rutas mediante composable

La función composable(route, arguments, deepLinks, enterTransition, exitTransition, content) registra una ruta en el grafo de NavHost. El parámetro route es una cadena que describe la ruta con marcadores de posición opcionales en forma {paramName}. El marcador se reemplaza con un valor real durante la navegación.

El bloque content de composable recibe un NavBackStackEntry del cual se extraen los argumentos. La función composable de la pantalla se renderiza solo cuando la ruta actual de NavController coincide con la ruta. Si no coincide, el composable se elimina de la composición, pero su estado puede conservarse mediante rememberSaveable o ViewModel con SavedStateHandle.

kotlin
composable(
    route = "article/{articleId}",
    arguments = listOf(navArgument("articleId") {
        type = NavType.IntType
        defaultValue = 0
    }),
    deepLinks = listOf(navDeepLink { uriPattern = "https://app.example/article/{articleId}" })
) { backStackEntry ->
    val articleId = backStackEntry.arguments?.getInt("articleId") ?: 0
    ArticleScreen(articleId = articleId)
}

El número de entradas composable dentro de NavHost puede variar desde unas pocas hasta cientos. Para aplicaciones grandes, las rutas se dividen en módulos y se conectan mediante grafos anidados. Cada composable puede tener su propia configuración de animación, deep links y argumentos.

Argumentos y parámetros de ruta tipados

Los argumentos de ruta se definen mediante el parámetro arguments: List<NamedNavArgument> en composable(). Cada argumento se define mediante navArgument(name) { type; defaultValue }. NavType determina el tipo de argumento: StringType, IntType, LongType, FloatType, BoolType, ParcelableType y ReferenceType.

Parámetro de rutaEjemplo de rutaNavType
Ruta (path)"user/{id}"NavType.IntType
Consulta (query)"search?q={query}"NavType.StringType
Opcional"details/{id}?tab={tab}"StringType + defaultValue=""
Parcelable"checkout/{order}"NavType.ParcelableType

Los argumentos se extraen de NavBackStackEntry mediante arguments?.getInt("id"). Para argumentos obligatorios, defaultValue puede omitirse — NavType usará null. Para argumentos opcionales, defaultValue debe establecerse, de lo contrario la navegación lanzará una excepción si el parámetro falta.

Desde Navigation 2.8.0, se recomienda la navegación Type-Safe: defina una clase sellada o clase de datos para las rutas con Kotlin Serialization. En lugar de una ruta de cadena, use composable<RouteType> { backStackEntry -> }. Esto elimina errores tipográficos en las rutas y genera automáticamente NavType para los argumentos. Para migrar, agregue la dependencia navigation-compose-typesafe y el plugin Kotlin Serialization.

Grafos de navegación anidados

nested graphs — un mecanismo para agrupar rutas dentro de NavHost mediante la función navigation(route, startDestination). Un grafo anidado tiene su propio prefijo de ruta y startDestination, y todas sus rutas son accesibles a través del prefijo. Los grafos anidados se utilizan para arquitectura modular, donde cada módulo de funcionalidad registra su propio subgrafo.

Beneficios de los grafos anidados: aislamiento de rutas dentro de un módulo, una pila de retroceso unificada para un grupo de pantallas y la capacidad de navegar por prefijo sin exponer la estructura interna. Por ejemplo, el grafo "auth" contiene "auth/login" y "auth/register". La navegación es posible tanto por la ruta completa como por prefijo con redirección a startDestination.

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) }
    }
}

Los grafos anidados admiten el paso de argumentos a nivel de grafo: los parámetros declarados en la ruta del grafo se pasan a todas las rutas internas. Para limpiar un grafo anidado, use popBackStack(route) — eliminará todas las entradas internas. Los grafos anidados no tienen límite de profundidad, pero se recomienda no más de 3 niveles para facilitar la lectura.

Personalización de animaciones y transiciones

NavHost admite animaciones de transición entre rutas composable mediante los parámetros enterTransition, exitTransition, popEnterTransition y popExitTransition. Las animaciones se establecen una vez para NavHost y se aplican a todas las rutas, o individualmente para cada composable. Por defecto, las animaciones están desactivadas.

Configuración típica: enterTransition = slideInHorizontally(initialOffsetX = { it }) — la pantalla se desliza desde la derecha; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — la pantalla se desliza hacia la izquierda. Para la animación pop, las direcciones se invierten: la pantalla se desliza desde la izquierda y se desliza hacia la derecha. Para BottomNavigation, se usa fadeIn/fadeOut sin deslizamiento.

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

Las animaciones personalizadas se crean mediante Compose Animation API: AnimatedContentTransitionScope proporciona acceso a las dimensiones del contenedor, el progreso de la animación y la dirección. Para transiciones de elementos compartidos (un elemento que se mueve suavemente a otra pantalla), se requiere la biblioteca Accompanist Navigation Animation o una implementación personalizada mediante sharedElement Modifier. Según Android Developers (2025), la animación de deslizamiento predeterminada (entrada desde la derecha, salida hacia la izquierda) se usa en el 80% de las aplicaciones Android con navegación.

Preguntas Frecuentes

¿Se pueden usar varios NavHost en una misma Activity?

Técnicamente sí, pero no se recomienda. Cada NavHost crea una pila de retroceso independiente, lo que rompe la navegación unificada. La excepción son áreas separadas, como un NavHost para el contenido principal y un NavHost para un BottomSheet con su propia navegación.

¿En qué se diferencia NavHost de Scaffold en Compose?

NavHost es un contenedor de navegación que cambia de pantallas. Scaffold es el diseño de toda la página (TopAppBar, BottomNavigation, FloatingActionButton). Normalmente, NavHost se coloca dentro de Scaffold.content. Scaffold no gestiona la navegación, solo proporciona espacios para componentes de UI.

¿Cómo compartir un ViewModel entre pantallas a través de NavHost?

Un ViewModel se crea dentro de un NavBackStackEntry mediante viewModel(). Para compartir un ViewModel entre pantallas, use parentNavController: vincule el ViewModel compartido a la entrada padre. Una alternativa es DI (Hilt/Koin) con ámbito de NavGraph.

¿Por qué NavHost recrea el composable en cada navegación?

Este es un comportamiento normal — NavHost elimina el composable de la composición al salir de una ruta. Para conservar el estado, use rememberSaveable para el estado de UI y ViewModel con SavedStateHandle para la lógica de negocio.

¿Cómo añadir manejo de 404 (ruta desconocida) en NavHost?

Añada una ruta final composable("404") y navegue a ella cuando se reciba un deep link desconocido. NavHost no tiene una ruta catch-all — verifique la ruta en el manejador de intención Deep Link antes de navigate(). Si la ruta no se encuentra, navegue a 404.

Resumen

  • NavHost — un contenedor composable de Navigation Compose que vincula NavController con un grafo de rutas y renderiza la pantalla actual
  • composable() registra una ruta con ruta, argumentos (NavType), deep links y animaciones
  • startDestination — la ruta inicial que se abre al iniciar NavHost por primera vez
  • Argumentos se pasan mediante marcadores {param} con NavType para tipado y defaultValue para parámetros opcionales
  • Grafos anidados mediante navigation() permiten agrupar rutas por módulos con una pila de retroceso aislada
  • Animación de transiciones se configura mediante enterTransition/exitTransition usando Compose Animation API
  • NavHost maneja automáticamente el botón de retroceso, la conservación del estado y los deep links sin código 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