Compila navegación adaptable

La mayoría de las apps tienen algunos destinos de nivel superior a los que se puede acceder a través de la IU de navegación principal de la app. En ventanas compactas, como una pantalla estándar de teléfono, los destinos suelen mostrarse en una barra de navegación en la parte inferior de la ventana. En una ventana expandida, como una app de pantalla completa en una tablet, un riel de navegación junto a la app suele ser una mejor opción, ya que es más fácil acceder a los controles de navegación mientras se mantiene presionado el lado izquierdo y el derecho del dispositivo.

NavigationSuiteScaffold simplifica el cambio entre IUs de navegación, ya que muestra la IU de navegación componible correspondiente en función de WindowSizeClass. Esto incluye el cambio dinámico de la IU durante los cambios de tamaño de la ventana de tiempo de ejecución. El comportamiento predeterminado es mostrar cualquiera de los siguientes componentes de la IU:

  • Barra de navegación si el ancho o la altura son compactos, o si el dispositivo está en posición de mesa
  • Riel de navegación para todo lo demás
Figura 1: NavigationSuiteScaffold muestra una barra de navegación en ventanas compactas.
Figura 2: NavigationSuiteScaffold muestra un riel de navegación en ventanas expandidas.

Agrega dependencias

NavigationSuiteScaffold es parte de la biblioteca del paquete de navegación adaptable de Material3. Agrega una dependencia para la biblioteca en el archivo build.gradle de tu app o módulo:

Kotlin


implementation("androidx.compose.material3:material3-adaptive-navigation-suite")

Groovy


implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'

Crea un andamiaje

Las dos partes principales de NavigationSuiteScaffold son los elementos del paquete de navegación y el contenido del destino seleccionado. Puedes definir directamente los elementos del paquete de navegación en un elemento componible, pero es común tenerlos en otro lugar, por ejemplo, en una enumeración:

enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
    SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
    PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}

Para usar NavigationSuiteScaffold, debes realizar un seguimiento del destino actual. Puedes hacerlo mediante rememberSaveable:

var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }

En el siguiente ejemplo, el parámetro navigationSuiteItems (tipo NavigationSuiteScope usa su función item para definir la IU de navegación de un destino individual). La IU de destino se usa en barras de navegación, rieles y paneles laterales. Para crear elementos de navegación, aplica un bucle a tu AppDestinations (definido en el fragmento anterior):

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it }
            )
        }
    }
) {
    // TODO: Destination content.
}

Dentro de la lambda de contenido de destino, usa el valor currentDestination para decidir qué IU mostrar. Si utilizas una biblioteca de navegación en tu app, úsala aquí para mostrar el destino adecuado. Una sentencia when puede ser suficiente:

NavigationSuiteScaffold(
    navigationSuiteItems = { /*...*/ }
) {
    // Destination content.
    when (currentDestination) {
        AppDestinations.HOME -> HomeDestination()
        AppDestinations.FAVORITES -> FavoritesDestination()
        AppDestinations.SHOPPING -> ShoppingDestination()
        AppDestinations.PROFILE -> ProfileDestination()
    }
}

Cambiar colores

NavigationSuiteScaffold crea un objeto Surface en toda el área que ocupa el andamiaje (por lo general, la ventana completa). Además, el andamiaje dibuja la IU de navegación específica, como un NavigationBar. Tanto la superficie como la IU de navegación usan los valores especificados en el tema de tu app, pero puedes anular los valores del tema.

El parámetro containerColor especifica el color de la superficie. El valor predeterminado es el color de fondo de tu esquema de colores. El parámetro contentColor especifica el color del contenido en esa superficie. El valor predeterminado es el color "activado" de lo que se especifique para containerColor. Por ejemplo, si containerColor usa el color background, contentColor usa el color onBackground. Consulta Temas de Material Design 3 en Compose para obtener más detalles sobre cómo funciona el sistema de colores. Cuando anules estos valores, usa valores definidos en tu tema para que la app admita los modos de pantalla oscuro y claro:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    containerColor = MaterialTheme.colorScheme.primary,
    contentColor = MaterialTheme.colorScheme.onPrimary,
) {
    // Content...
}

La IU de navegación se dibuja frente a la superficie NavigationSuiteScaffold. NavigationSuiteDefaults.colors() proporciona los valores predeterminados para los colores de la IU, pero también puedes anular estos valores. Por ejemplo, si deseas que el fondo de la barra de navegación sea transparente, pero los demás valores sean los predeterminados, anula navigationBarContainerColor:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    navigationSuiteColors = NavigationSuiteDefaults.colors(
        navigationBarContainerColor = Color.Transparent,
    )
) {
    // Content...
}

En última instancia, puedes personalizar cada elemento en la IU de navegación. Cuando llamas a la función item, puedes pasar una instancia de NavigationSuiteItemColors. Esta clase especifica los colores para los elementos de una barra de navegación, un riel y un panel lateral de navegación. Eso significa que puedes tener colores idénticos en cada tipo de IU de navegación o puedes variar los colores según tus necesidades. Define los colores en el nivel de NavigationSuiteScaffold para usar la misma instancia de objeto para todos los elementos y llama a la función NavigationSuiteDefaults.itemColors() para anular solo los que deseas cambiar:

val myNavigationSuiteItemColors = NavigationSuiteDefaults.itemColors(
    navigationBarItemColors = NavigationBarItemDefaults.colors(
        indicatorColor = MaterialTheme.colorScheme.primaryContainer,
        selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer
    ),
)

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it },
                colors = myNavigationSuiteItemColors,
            )
        }
    },
) {
    // Content...
}

Cómo personalizar los tipos de navegación

El comportamiento predeterminado de NavigationSuiteScaffold cambia la IU de navegación en función de las clases de tamaño de ventana. Sin embargo, te recomendamos que anules este comportamiento. Por ejemplo, si tu app muestra un panel de contenido grande único para un feed, podría usar un panel lateral de navegación permanente para ventanas expandidas, pero aun así recurrir al comportamiento predeterminado para las clases de tamaño de ventana compacta y mediana:

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    layoutType = customNavSuiteType,
) {
    // Content...
}

Recursos adicionales

Consulta la guía de Material Design:

Consulta los siguientes componentes de la biblioteca androidx.compose.material3: