Adaptive Navigation erstellen

Die meisten Apps haben einige Ziele der obersten Ebene, auf die über die primäre Navigations-UI der App zugegriffen werden kann. In kompakten Fenstern, z. B. auf einem Standard-Smartphone-Display, werden die Ziele in der Regel in einer Navigationsleiste unten im Fenster angezeigt. In einem erweiterten Fenster, z. B. einer Vollbild-App auf einem Tablet, ist ein Navigationsstreifen neben der App normalerweise die bessere Wahl, da die Navigationselemente leichter zu erreichen sind, wenn Sie das Gerät links und rechts halten.

NavigationSuiteScaffold vereinfacht das Wechseln zwischen Navigations-UIs, indem die entsprechende zusammensetzbare Navigations-UI basierend auf WindowSizeClass angezeigt wird. Dazu gehört auch das dynamische Ändern der UI bei Änderungen der Fenstergröße zur Laufzeit. Standardmäßig wird eine der folgenden UI-Komponenten angezeigt:

  • Navigationsleiste , wenn die Breite oder Höhe kompakt ist oder sich das Gerät in der Tischposition befindet
  • Navigationsstreifen für alle anderen Fälle
Abbildung 1 NavigationSuiteScaffold zeigt in kompakten Fenstern eine Navigationsleiste an.
Abbildung 2 NavigationSuiteScaffold zeigt in erweiterten Fenstern einen Navigationsstreifen an.

Abhängigkeiten hinzufügen

NavigationSuiteScaffold ist Teil der adaptiven Navigationssuite-Bibliothek von Material 3. Fügen Sie in der Datei build.gradle Ihrer App oder Ihres Moduls eine Abhängigkeit für die Bibliothek hinzu:

Kotlin

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

Groovy

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

Scaffold erstellen

Die beiden Hauptteile von NavigationSuiteScaffold sind die Elemente der Navigationssuite und der Inhalt für das ausgewählte Ziel. Sie können die Elemente der Navigationssuite direkt in einer zusammensetzbaren Funktion definieren. In der Regel werden sie jedoch an anderer Stelle definiert, z. B. in einer Enum:

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

Wenn Sie NavigationSuiteScaffold verwenden möchten, müssen Sie das aktuelle Ziel verfolgen. Dazu können Sie rememberSaveable verwenden:

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

Im folgenden Beispiel verwendet der navigationSuiteItems Parameter (Typ NavigationSuiteScope) die Funktion item, um die Navigations-UI für ein einzelnes Ziel zu definieren. Die Ziel-UI wird in Navigationsleisten, Navigationsstreifen und Navigationsleisten verwendet. Um Navigationselemente zu erstellen, durchlaufen Sie AppDestinations (im vorherigen Snippet definiert):

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

Verwenden Sie in der Lambda-Funktion für den Zielinhalt den Wert currentDestination, um zu entscheiden, welche UI angezeigt werden soll. Wenn Sie in Ihrer App eine Navigationsbibliothek verwenden, verwenden Sie sie hier, um das entsprechende Ziel anzuzeigen. Eine „when“-Anweisung kann ausreichen:

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

Farben ändern

NavigationSuiteScaffold erstellt eine Surface über den gesamten Bereich den das Scaffold einnimmt, in der Regel das gesamte Fenster. Außerdem zeichnet das Scaffold die jeweilige Navigations-UI, z. B. eine NavigationBar. Sowohl die Oberfläche als auch die Navigations-UI verwenden die im Design Ihrer App angegebenen Werte. Sie können die Designwerte jedoch überschreiben.

Der Parameter containerColor gibt die Farbe der Oberfläche an. Standardmäßig ist das die Hintergrundfarbe Ihres Farbschemas. Der Parameter contentColor gibt die Farbe des Inhalts auf dieser Oberfläche an. Standardmäßig ist das die „on“-Farbe von dem, was für containerColor angegeben ist. Wenn containerColor beispielsweise die Farbe background verwendet, verwendet contentColor die Farbe onBackground. Weitere Informationen zur Funktionsweise des Farbsystems finden Sie unter Material Design 3-Design in Compose. Wenn Sie diese Werte überschreiben, verwenden Sie Werte, die in Ihrem Design definiert sind, damit Ihre App den dunklen und hellen Anzeigemodus unterstützt:

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

Die Navigations-UI wird vor der NavigationSuiteScaffold-Oberfläche gezeichnet. Die Standardwerte für die UI-Farben werden von NavigationSuiteDefaults.colors() bereitgestellt. Sie können diese Werte jedoch auch überschreiben. Wenn der Hintergrund der Navigationsleiste beispielsweise transparent sein soll, die anderen Werte aber die Standardwerte sein sollen, überschreiben Sie navigationBarContainerColor:

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

Letztendlich können Sie jedes Element in der Navigations-UI anpassen. Wenn Sie die item Funktion aufrufen, können Sie eine Instanz von NavigationSuiteItemColors übergeben. Die Klasse gibt die Farben für Elemente in einer Navigationsleiste, einem Navigationsstreifen und einer Navigationsleiste an. Das bedeutet, dass Sie für alle Navigations-UI-Typen identische Farben verwenden oder die Farben nach Bedarf variieren können. Definieren Sie die Farben auf der Ebene NavigationSuiteScaffold, um dieselbe Objektinstanz für alle Elemente zu verwenden, und rufen Sie die Funktion NavigationSuiteDefaults.itemColors() auf, um nur die gewünschten Farben zu überschreiben:

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

Navigationstypen anpassen

Das Standardverhalten von NavigationSuiteScaffold ändert die Navigations-UI basierend auf Fenstergrößenklassen. Sie können dieses Verhalten jedoch überschreiben. Wenn Ihre App beispielsweise einen einzelnen großen Bereich mit Inhalten für einen Feed anzeigt, könnte die App für erweiterte Fenster eine permanente Navigationsleiste verwenden, aber für kompakte und mittlere Fenstergrößenklassen auf das Standardverhalten zurückgreifen:

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND)) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

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

Zusätzliche Ressourcen