Creare una navigazione adattiva

La maggior parte delle app ha alcune destinazioni di primo livello accessibili tramite la relativa UI di navigazione principale. Nelle finestre compatte, come il display di un telefono standard, le destinazioni sono in genere visualizzate in una barra di navigazione nella parte inferiore della finestra. In una finestra espansa, ad esempio un'app a schermo intero su un tablet, la barra di navigazione accanto all'app è in genere la scelta migliore, in quanto i controlli di navigazione sono più facili da raggiungere tenendo premuti i lati sinistro e destro del dispositivo.

NavigationSuiteScaffold semplifica il passaggio da un'interfaccia utente di navigazione all'altra mostrando l'interfaccia componibile di navigazione appropriata in base a WindowSizeClass. Ciò include la modifica dinamica dell'interfaccia utente durante le modifiche alle dimensioni della finestra di runtime. Il comportamento predefinito prevede la visualizzazione di uno dei seguenti componenti dell'interfaccia utente:

  • Barra di navigazione se la larghezza o l'altezza sono compatte o se il dispositivo si trova nella posizione da tavolo.
  • Barra di navigazione per tutto il resto
Figura 1. NavigationSuiteScaffold visualizza una barra di navigazione nelle finestre compatte.
Figura 2. NavigationSuiteScaffold mostra una rotaia di navigazione nelle finestre espanse.

Aggiungi dipendenze

NavigationSuiteScaffold fa parte della raccolta della suite di navigazione adattiva Material3. Aggiungi una dipendenza per la libreria nel file build.gradle dell'app o del modulo:

Kotlin


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

trendy


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

Crea un sostegno

Le due parti principali di NavigationSuiteScaffold sono gli elementi della suite di navigazione e i contenuti della destinazione selezionata. Puoi definire direttamente gli elementi della suite di navigazione in un componibile, ma è pratica comune definire questi elementi altrove, ad esempio in un'enumerazione:

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

Per utilizzare NavigationSuiteScaffold, devi monitorare la destinazione corrente, operazione che puoi eseguire con rememberSaveable:

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

Nell'esempio seguente, il parametro navigationSuiteItems (tipo NavigationSuiteScope utilizza la propria funzione item per definire l'interfaccia utente di navigazione per una singola destinazione. La UI di destinazione viene utilizzata per barre di navigazione, binari e riquadri a scomparsa. Per creare elementi di navigazione, esegui lo loop di AppDestinations (definito nello snippet precedente):

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

Nella funzione lambda dei contenuti di destinazione, utilizza il valore currentDestination per decidere quale UI visualizzare. Se utilizzi una libreria di navigazione nella tua app, usala qui per visualizzare la destinazione appropriata. Una dichiarazione quando può essere sufficiente:

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

Cambia colori

NavigationSuiteScaffold crea un Surface sull'intera area occupata dall'impalcatura, in genere l'intera finestra. Inoltre, lo scaffold traccia la specifica UI di navigazione, ad esempio NavigationBar. Sia la superficie sia l'interfaccia utente di navigazione utilizzano i valori specificati nel tema dell'app, ma puoi eseguire l'override dei valori del tema.

Il parametro containerColor specifica il colore della superficie. Il valore predefinito è il colore di sfondo della combinazione di colori. Il parametro contentColor specifica il colore dei contenuti sulla superficie. Il valore predefinito è il colore "on" di quello specificato per containerColor. Ad esempio, se containerColor usa il colore background, contentColor utilizza il colore onBackground. Per ulteriori dettagli sul funzionamento del sistema di colori, consulta la sezione Temi di Material Design 3 in Compose. Quando esegui l'override di questi valori, utilizza i valori definiti nel tema in modo che l'app supporti le modalità di visualizzazione Buio e chiaro:

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

L'interfaccia utente di navigazione è disegnata davanti alla superficie NavigationSuiteScaffold. I valori predefiniti per i colori dell'interfaccia utente sono forniti da NavigationSuiteDefaults.colors(), ma puoi anche sostituirli. Ad esempio, se vuoi che lo sfondo della barra di navigazione sia trasparente, ma gli altri valori siano quelli predefiniti, esegui l'override di navigationBarContainerColor:

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

In definitiva, puoi personalizzare ogni elemento nell'interfaccia utente di navigazione. Quando chiami la funzione item, puoi passare un'istanza di NavigationSuiteItemColors. La classe specifica i colori degli elementi in una barra di navigazione, nella barra di navigazione e nel riquadro di navigazione. Ciò significa che i colori possono essere identici per tutti i tipi di UI di navigazione oppure puoi variare i colori in base alle tue esigenze. Definisci i colori a livello NavigationSuiteScaffold per utilizzare la stessa istanza dell'oggetto per tutti gli elementi e chiama la funzione NavigationSuiteDefaults.itemColors() per sostituire solo quelli che vuoi modificare:

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

Personalizza i tipi di navigazione

Il comportamento predefinito di NavigationSuiteScaffold modifica l'interfaccia utente di navigazione in base alle classi dimensioni finestra. Tuttavia, è consigliabile eseguire l'override di questo comportamento. Ad esempio, se la tua app mostra un unico riquadro di contenuti di grandi dimensioni per un feed, potrebbe utilizzare un riquadro a scomparsa di navigazione permanente per le finestre espanse, ma ricorrere comunque al comportamento predefinito per le classi di dimensioni compatte e medie:

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

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

Risorse aggiuntive

Consulta le indicazioni relative a Material Design:

Vedi i seguenti componenti della libreria androidx.compose.material3: