Criar uma navegação adaptável

A maioria dos apps tem alguns destinos de nível superior que podem ser acessados pela interface de navegação principal do app. Em janelas compactas, como em uma tela padrão de smartphone, os destinos normalmente são mostrados em uma barra de navegação na parte de baixo da janela. Em uma janela expandida, como um app de tela cheia em um tablet, uma coluna de navegação ao lado do app geralmente é uma opção melhor, já que os controles de navegação são mais fáceis de acessar com os lados esquerdo e direito do dispositivo.

O NavigationSuiteScaffold simplifica a alternância entre IUs de navegação, mostrando o elemento combinável adequado com base em WindowSizeClass. Isso inclui mudar dinamicamente a interface durante mudanças no tamanho da janela de execução. O comportamento padrão é mostrar um dos componentes de interface abaixo:

  • Barra de navegação se a largura ou a altura for compacta ou se o dispositivo estiver na posição de mesa
  • Coluna de navegação para todo o restante
Figura 1. O NavigationSuiteScaffold mostra uma barra de navegação em janelas compactas.
Figura 2. NavigationSuiteScaffold mostra uma coluna de navegação em janelas expandidas.

Adicionar dependências

O NavigationSuiteScaffold faz parte da biblioteca do pacote de navegação adaptável do Material3 (link em inglês). Adicione uma dependência para a biblioteca no arquivo build.gradle do seu app ou módulo:

Kotlin


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

Groovy


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

Criar um scaffold

As duas partes principais do NavigationSuiteScaffold são os itens do pacote de navegação e o conteúdo do destino selecionado. Você pode definir diretamente os itens do pacote de navegação em um elemento combinável, mas é comum fazer isso em outro lugar, por exemplo, em um tipo enumerado:

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, você precisa rastrear o destino atual, o que pode ser feito com rememberSaveable:

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

No exemplo a seguir, o parâmetro navigationSuiteItems (tipo NavigationSuiteScope) usa a função item para definir a IU de navegação para um destino individual. A interface de destino é usada em barras de navegação, colunas e gavetas. Para criar itens de navegação, use a repetição do AppDestinations (definido no snippet 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.
}

Na lambda de conteúdo de destino, use o valor currentDestination para decidir qual interface vai ser mostrada. Se você usa uma biblioteca de navegação no seu app, use-a aqui para mostrar o destino adequado. Uma instrução when pode ser suficiente:

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

Mudar de cor

NavigationSuiteScaffold cria um Surface em toda a área ocupada pelo scaffold, normalmente a janela cheia. Além disso, o scaffold desenha a interface de navegação específica, como um NavigationBar. Tanto a superfície quanto a interface de navegação usam os valores especificados no tema do app, mas você pode substituir os valores do tema.

O parâmetro containerColor especifica a cor da superfície. O padrão é a cor de fundo do seu esquema de cores. O parâmetro contentColor especifica a cor do conteúdo nessa plataforma. O padrão é a cor "ativada" do que for especificado para containerColor. Por exemplo, se containerColor usar a cor background, contentColor usará a cor onBackground. Consulte Temas do Material Design 3 no Compose para mais detalhes sobre como o sistema de cores funciona. Ao substituir esses valores, use valores definidos no tema para que o app ofereça suporte aos modos de exibição escuro e claro:

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

A interface de navegação é desenhada na frente da superfície NavigationSuiteScaffold. Os valores padrão para as cores da interface são fornecidos por NavigationSuiteDefaults.colors(), mas você também pode substituir esses valores. Por exemplo, se você quiser que o plano de fundo da barra de navegação seja transparente, mas os outros valores sejam os padrões, substitua navigationBarContainerColor:

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

Por fim, você pode personalizar cada item na interface de navegação. Ao chamar a função item, você pode transmitir uma instância de NavigationSuiteItemColors. A classe especifica as cores de itens em uma barra, coluna e gaveta de navegação. Isso significa que você pode ter cores idênticas em cada tipo de interface de navegação ou variar as cores de acordo com suas necessidades. Defina as cores no nível do NavigationSuiteScaffold para usar a mesma instância de objeto para todos os itens e chame a função NavigationSuiteDefaults.itemColors() para substituir apenas as que você quer mudar:

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

Personalizar tipos de navegação

O comportamento padrão de NavigationSuiteScaffold muda a interface de navegação com base nas classes de tamanho da janela. No entanto, é possível modificar esse comportamento. Por exemplo, se o app mostrar um único painel grande de conteúdo para um feed, ele poderá usar uma gaveta de navegação permanente para janelas expandidas, mas ainda retornar ao comportamento padrão para classes de tamanho de janela compacta e média:

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

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

Outros recursos

Consulte as orientações do Material Design:

Confira os seguintes componentes da biblioteca androidx.compose.material3: