Navegación entre pantallas con Compose Navigation

  • Implementación de NavHost y NavController para gestionar el flujo de pantallas en Compose.
  • Uso de rutas seguras y paso de argumentos mediante el nuevo sistema de seguridad de tipos con @Serializable.
  • Integración de navegación avanzada incluyendo popBackStack y el lanzamiento de Intents externos.
  • Adaptación de la navegación para entornos multiplataforma Android e iOS mediante Compose Multiplatform.

Navegación entre pantallas con Compose Navigation

Si te estás metiendo en el mundo de Jetpack Compose, habrás notado que es un cambio de chip bastante fuerte. No se trata solo de escribir código distinto, sino de repensar la arquitectura de la interfaz de usuario, y aquí es donde entra en juego la navegación, que es básicamente el pegamento que une todas las pantallas de tu aplicación.

Moverse entre diferentes piezas de contenido, ya sea dentro de la propia app o saltando a herramientas externas, es fundamental para que la experiencia sea fluida. Para lograrlo, Android nos ofrece el componente Navigation de Jetpack, que incluye herramientas como la biblioteca de Navigation y el complemento Safe Args de Gradle, asegurando que el usuario no se pierda y que el comportamiento sea siempre predecible.

Conceptos fundamentales para no perderse

Para empezar a manejarte, tienes que conocer a los protagonistas de este sistema. El Host de navegación es el elemento de la interfaz que actúa como contenedor, intercambiando los destinos según el usuario interactúe. Por otro lado, el Gráfico de navegación (NavGraph) es la estructura de datos que define todos los puntos de llegada y cómo se conectan entre sí.

El cerebro de todo es el NavController, que es el coordinador central. Este objeto es el que te permite ejecutar los saltos entre pantallas, gestionar la pila de actividades y controlar los vínculos directos. Para que esto funcione, cada nodo en el gráfico se llama Destino (NavDestination), y para llegar a ellos utilizamos una Ruta, que es básicamente un identificador único en formato de cadena de texto, muy parecido a una URL de una web.

Este sistema no solo sirve para cambiar la vista, sino que aporta beneficios extra como animaciones y transiciones estandarizadas, soporte para paneles laterales o navegación inferior y una compatibilidad total con ViewModel para compartir datos entre pantallas sin complicaciones.

mvvm
Artículo relacionado:
MVVM: El patrón de arquitectura de software definitivo para apps modernas

Configuración del entorno y frameworks

Dependiendo de cómo esté construida tu app, tienes dos caminos. Si vas a tope con Compose, lo ideal es usar Navigation Compose, donde cada destino es un elemento componible. Si todavía arrastras Fragmentos o usas una mezcla de vistas XML y Compose, lo más sensato es seguir con la navegación basada en fragmentos mientras haces la migración progresiva.

Para ponerte manos a la obra, lo primero es añadir las dependencias necesarias en el archivo build.gradle utilizando Android Studio. Una vez hecho esto, puedes empezar a definir tu estructura. Una técnica muy limpia para gestionar las rutas es utilizar una clase de tipo enum, lo que evita errores tipográficos al escribir las rutas una y otra vez por todo el código.

Montando el NavHost y gestionando rutas

Navegación entre pantallas con Compose Navigation

El NavHost es el componente que decide qué pantalla mostrar según la ruta activa. Para configurarlo, necesitas una instancia de NavHostController, que normalmente se obtiene mediante rememberNavController(). Además, debes definir un destino de inicio (startDestination) para que la app sepa qué mostrar al abrirse por primera vez.

Kotlin vs Java para programar apps Android
Artículo relacionado:
Kotlin vs Java: Comparativa definitiva para programar apps Android

Dentro del NavHost, utilizamos la función composable() para asignar una ruta a un componente específico. Por ejemplo, si estamos creando una app de pedidos, podríamos tener rutas para el inicio, la selección de sabores y el resumen. Es vital pasar el estado del ViewModel a estos componibles para que la información (como el precio total) se actualice en tiempo real mientras el usuario navega.

Un detalle importante es que no conviene pasar el navController a cada pantalla, ya que esto rompería la reusabilidad y complicaría los tests. Lo mejor es pasar lambdas de eventos (como onNextButtonClicked) para que la lógica de navegación se quede centralizada en el NavHost y las pantallas sean independientes.

Navegación avanzada y control de la pila

Para saltar de una pantalla a otra, usamos el método navigate() pasando la ruta del destino. Pero ojo, cada vez que haces esto, la pantalla se añade a la pila de actividades. Si el usuario pulsa el botón atrás del sistema, regresará a la anterior, un proceso íntimamente ligado al ciclo de vida de una activity en Android. Sin embargo, a veces necesitamos un botón de cancelar que nos lleve directamente al inicio, limpiando todo el rastro.

Para lograr este efecto, utilizamos popBackStack(). Al indicar la ruta de inicio y marcar inclusive = false, el sistema elimina todos los destinos intermedios, dejando la pantalla de inicio como la única visible. Esto es fundamental para resetear flujos de trabajo complejos sin dejar pantallas huérfanas en la memoria.

android keystore-4
Artículo relacionado:
Android Keystore: Seguridad, Gestión y Mejores Prácticas en Android

Interacción con aplicaciones externas mediante Intents

No todo ocurre dentro de nuestra app. A veces necesitamos lanzar una acción del sistema, como compartir un resumen de pedido. Para esto no usamos el NavController, sino los Intents de Android. Un Intent es básicamente una petición al sistema operativo para realizar una acción específica.

Para compartir contenido, se utiliza el ACTION_SEND. Es necesario configurar el tipo de datos (MIME type), como "text/plain", y añadir extras como el asunto y el texto del mensaje mediante putExtra(). Finalmente, se envuelve todo en un Intent.createChooser() para que el usuario pueda elegir con qué aplicación quiere compartir la información.

Haciendo que la barra de herramientas sea dinámica

Para que la app se sienta profesional, la AppBar debe reaccionar a la navegación. Esto implica que el título cambie según la pantalla actual y que aparezca el botón de retroceso (botón Up) solo cuando haya una pantalla previa en la pila.

Podemos lograr esto observando el estado de la pila con currentBackStackEntryAsState(). Si el previousBackStackEntry no es nulo, significa que el usuario ha avanzado en la navegación y, por lo tanto, debemos mostrar el icono de la flecha hacia atrás y ejecutar navController.navigateUp() al hacer clic en él.

Activar la barra de navegación transparente
Artículo relacionado:
Cómo activar la barra de navegación transparente en las apps de Android

Navegación en entornos Multiplatform

Con la llegada de Compose Multiplatform, ahora podemos compartir la lógica de navegación entre Android e iOS. La arquitectura sigue siendo la misma (NavController, NavHost y NavGraph), pero adaptada para funcionar en múltiples sistemas operativos desde un único código fuente en Kotlin.

A partir de la versión 2.8.0 de Navigation, se ha introducido una mejora brutal: la seguridad de tipos. Ya no hace falta pelearse con cadenas de texto para las rutas; ahora podemos usar clases de datos anotadas con @Serializable. Esto significa que los argumentos se pasan como objetos reales, eliminando los errores tipográficos y permitiendo que el compilador detecte fallos antes incluso de ejecutar la app.

Para que todo esto funcione como la seda, es recomendable crear una capa de abstracción de navegación, separando la lógica de negocio de la interfaz. Así, el código es más mantenible, testeable y escalable, especialmente cuando la aplicación empieza a crecer y aparecen los grafos de navegación anidados.

La implementación de un sistema de rutas sólido, el uso de la pila de retroceso para gestionar el flujo del usuario y la adopción de las nuevas herramientas de tipado seguro permiten crear aplicaciones robustas y coherentes, independientemente de si se despliegan en un dispositivo Android o en un iPhone.

como configurar la relación de aspecto en móviles plegables
Artículo relacionado:
Cómo cambiar la relación de aspecto en apps para dispositivos plegables

Add as preferred source