La navegación describe la forma en que los usuarios se mueven por tu app. Los usuarios interactúan con los elementos de la IU, por lo general, presionando o haciendo clic en ellos, y la app responde mostrando contenido nuevo. Si el usuario quiere volver al contenido anterior, usa el gesto atrás o presiona el botón Atrás.
Cómo modelar el estado de navegación
Una forma conveniente de modelar este comportamiento es con una pila de contenido. A medida que el usuario navega hacia adelante hacia contenido nuevo, este se coloca en la parte superior de la pila. Cuando el usuario vuelve de ese contenido, se quita de la pila y se muestra el contenido anterior. En términos de navegación, esta pila suele denominarse pila de actividades anteriores porque representa el contenido al que el usuario puede volver.

Cómo crear una pila de actividades
En Navigation 3, la pila de historial no contiene contenido. En su lugar, contiene referencias al contenido, conocidas como claves. Las claves pueden ser de cualquier tipo, pero suelen ser clases de datos serializables simples. Usar referencias en lugar de contenido tiene los siguientes beneficios:
- Es fácil navegar por ella, ya que se pueden insertar claves en la pila de actividades.
- Siempre que las claves sean serializables, la pila de elementos atrás se puede guardar en el almacenamiento persistente, lo que permite que sobreviva a los cambios de configuración y a la finalización del proceso. Esto es importante porque los usuarios esperan salir de tu app, volver a ella más tarde y retomar el contenido desde donde lo dejaron. Consulta Cómo guardar el historial de navegación para obtener más información.
Un concepto clave en la API de Navigation 3 es que tú eres propietario de la pila de actividades. La biblioteca:
- Se espera que tu pila de elementos atrás sea un
List<T>
respaldado por un estado de instantánea, en el queT
es el tipo de tukeys
de pila de elementos atrás. Puedes usarAny
o proporcionar tus propias claves con un tipo más fuerte. Cuando veas los términos "push" o "pop", la implementación subyacente es agregar o quitar elementos del final de una lista. - Observa la pila de actividades anterior y refleja su estado en la IU con un
NavDisplay
.
En el siguiente ejemplo, se muestra cómo crear claves y una pila de elementos atrás, y cómo modificar la pila de elementos atrás en respuesta a los eventos de navegación del usuario:
// Define keys that will identify content data object ProductList data class ProductDetail(val id: String) @Composable fun MyApp() { // Create a back stack, specifying the key the app should start with val backStack = remember { mutableStateListOf<Any>(ProductList) } // Supply your back stack to a NavDisplay so it can reflect changes in the UI // ...more on this below... // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state backStack.add(ProductDetail(id = "ABC")) // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state backStack.removeLastOrNull() }
Resuelve claves para el contenido
El contenido se modela en Navigation 3 con NavEntry
, que es una clase que contiene una función de componibilidad. Representa un destino, una sola pieza de contenido a la que el usuario puede navegar hacia adelante y hacia atrás.
Un objeto NavEntry
también puede contener metadatos, es decir, información sobre el contenido. Los objetos de contenedor, como NavDisplay
, pueden leer estos metadatos para decidir cómo mostrar el contenido de NavEntry
. Por ejemplo, los metadatos se pueden usar para anular las animaciones predeterminadas de un NavEntry
específico. NavEntry
metadata
es un mapa de claves String
a valores Any
, que proporciona un almacenamiento de datos versátil.
Para convertir un key
en un NavEntry
, crea un Entry Provider. Esta es una función que acepta un key
y devuelve un NavEntry
para ese key
. Por lo general, se define como un parámetro lambda cuando se crea un NavDisplay
.
Existen dos formas de crear un Entry Provider: crear una función lambda directamente o usar el DSL de entryProvider
.
Cómo crear directamente una función de Entry Provider
Por lo general, creas una función de Entry Provider con una instrucción when
, con una rama para cada una de tus claves.
entryProvider = { key -> when (key) { is ProductList -> NavEntry(key) { Text("Product List") } is ProductDetail -> NavEntry( key, metadata = mapOf("extraDataKey" to "extraDataValue") ) { Text("Product ${key.id} ") } else -> { NavEntry(Unit) { Text(text = "Invalid Key: $it") } } } }
Usa el DSL de entryProvider
El DSL de entryProvider
puede simplificar tu función lambda, ya que evita la necesidad de realizar pruebas con cada uno de tus tipos de clave y construir un NavEntry
para cada uno.
Usa la función del compilador de entryProvider
para ello. También incluye un comportamiento de resguardo predeterminado (generar un error) si no se encuentra la clave.
entryProvider = entryProvider { entry<ProductList> { Text("Product List") } entry<ProductDetail>( metadata = mapOf("extraDataKey" to "extraDataValue") ) { key -> Text("Product ${key.id} ") } }
Ten en cuenta lo siguiente del fragmento:
entry
se usa para definir unNavEntry
con el tipo y el contenido componible determinados.entry
acepta un parámetrometadata
para establecerNavEntry.metadata
Cómo mostrar la pila de actividades
La pila de actividades representa el estado de navegación de tu app. Cada vez que cambia la pila de actividades, la IU de la app debe reflejar el nuevo estado de la pila de actividades. En Navigation 3, un NavDisplay
observa tu pila de actividades y actualiza su IU según corresponda. Constrúyelo con los siguientes parámetros:
- Tu pila de elementos atrás: Debe ser del tipo
SnapshotStateList<T>
, en el queT
es el tipo de tus claves de pila de elementos atrás. Es unList
observable, por lo que activa la recomposición deNavDisplay
cuando cambia. - Un
entryProvider
para convertir las claves de tu pila de historial en objetosNavEntry
. - De manera opcional, proporciona una expresión lambda para el parámetro
onBack
. Se llama a este método cuando el usuario activa un evento de atrás.
En el siguiente ejemplo, se muestra cómo crear un objeto NavDisplay
.
data object Home data class Product(val id: String) @Composable fun NavExample() { val backStack = remember { mutableStateListOf<Any>(Home) } NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, entryProvider = { key -> when (key) { is Home -> NavEntry(key) { ContentGreen("Welcome to Nav3") { Button(onClick = { backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(key) { ContentBlue("Product ${key.id} ") } else -> NavEntry(Unit) { Text("Unknown route") } } } ) }
De forma predeterminada, el NavDisplay
muestra el NavEntry
superior en la pila de actividades en un diseño de un solo panel. En la siguiente grabación, se muestra la app en ejecución:

NavDisplay
comportamiento predeterminado con dos destinos.Resumen
En el siguiente diagrama, se muestra cómo fluyen los datos entre los distintos objetos de Navigation 3:

Los eventos de navegación inician cambios. Las claves se agregan o quitan de la pila de actividades en respuesta a las interacciones del usuario.
El cambio en el estado de la pila de actividades anterior activa la recuperación de contenido. El elemento
NavDisplay
(un elemento componible que renderiza una pila de actividades) observa la pila de actividades. En su configuración predeterminada, muestra la entrada superior de la pila de actividades en un diseño de un solo panel. Cuando cambia la clave superior en la pila de actividades,NavDisplay
usa esta clave para solicitar el contenido correspondiente del proveedor de entradas.El proveedor de entrada proporciona contenido. El proveedor de entrada es una función que resuelve una clave en un
NavEntry
. Cuando recibe una clave delNavDisplay
, el proveedor de entrada proporciona elNavEntry
asociado, que contiene tanto la clave como el contenido.Se muestra el contenido. El
NavDisplay
recibe elNavEntry
y muestra el contenido.