Utwórz adaptacyjną nawigację

Większość aplikacji ma kilka miejsc docelowych najwyższego poziomu, które są dostępne w głównym interfejsie nawigacji aplikacji. W kompaktowych oknach, np. na standardowym wyświetlaczu telefonu, miejsca docelowe są zwykle wyświetlane na pasku nawigacyjnym u dołu okna. W rozszerzonym oknie, np. w przypadku aplikacji pełnoekranowej na tablecie, zwykle lepszym wyborem jest pasek nawigacyjny obok aplikacji, ponieważ łatwiej jest uzyskać dostęp do elementów sterujących nawigacji, przytrzymując lewą i prawą stronę urządzenia.

NavigationSuiteScaffold upraszcza przełączanie się między interfejsami nawigacji, wyświetlając odpowiedni element kompozycyjny nawigacji na podstawie WindowSizeClass. Obejmuje to dynamiczną zmianę interfejsu w przypadku zmiany rozmiaru okna w czasie działania. Domyślnym zachowaniem jest wyświetlanie jednego z tych komponentów interfejsu:

  • paska nawigacyjnego, jeśli szerokość lub wysokość jest niewielka albo gdy urządzenie jest ustawione na stole;
  • Kolejki nawigacyjne we wszystkich innych miejscach
Rysunek 1. NavigationSuiteScaffold wyświetla pasek nawigacyjny w kompaktowych oknach.
Rysunek 2. NavigationSuiteScaffold wyświetla w rozwiniętych oknach pasek nawigacyjny.

Dodaj zależności

NavigationSuiteScaffold jest częścią biblioteki pakietu nawigacji adaptacyjnej Material3. Dodaj zależność dla biblioteki w pliku build.gradle aplikacji lub modułu:

Kotlin


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

Odlotowy


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

Utwórz rusztowanie

Dwie główne części usługi NavigationSuiteScaffold to elementy pakietu nawigacyjnego i treści dla wybranego miejsca docelowego. Elementy pakietu nawigacyjnego można definiować bezpośrednio w elemencie kompozycyjnym, ale często są one definiowane w innym miejscu, np. w wyliczeniu:

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

Aby użyć funkcji NavigationSuiteScaffold, musisz śledzić bieżące miejsce docelowe. Możesz to zrobić, korzystając z usługi rememberSaveable:

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

W tym przykładzie parametr navigationSuiteItems (typ NavigationSuiteScope używa swojej funkcji item do definiowania interfejsu nawigacji w przypadku danego miejsca docelowego). Interfejs docelowy jest używany między paskami nawigacyjnymi, szynami i szufladami. Aby utworzyć elementy nawigacji, zapętlasz element AppDestinations (zdefiniowany we wcześniejszym fragmencie):

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

W obiekcie lambda zawartości docelowej użyj wartości currentDestination, aby zdecydować, który interfejs ma się wyświetlać. Jeśli w swojej aplikacji używasz biblioteki nawigacji, użyj jej tutaj, aby wyświetlić odpowiednie miejsce docelowe. Kiedy wystarczy stwierdzenie:

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

Zmień kolory

NavigationSuiteScaffold tworzy element Surface obejmujący cały obszar, który zajmuje rusztowanie, zwykle całe okno. Dodatkowo tworzy w nim odpowiedni interfejs nawigacyjny, na przykład NavigationBar. Zarówno platforma, jak i interfejs nawigacyjny używają wartości określonych w motywie aplikacji, ale możesz zastąpić wartości motywu.

Parametr containerColor określa kolor powierzchni. Domyślnie jest to kolor tła schematu kolorów. Parametr contentColor określa kolor treści na tej platformie. Domyślnym kolorem jest „włączony” przy wszystkich elementach określonych w polu containerColor. Jeśli np. containerColor używa koloru background, contentColor używa koloru onBackground. Więcej informacji o systemie kolorów znajdziesz w artykule Tworzenie motywów Material Design 3 w sekcji Utwórz. Aby zastąpić te wartości, użyj wartości zdefiniowanych w motywie, aby aplikacja obsługiwała ciemne i jasne tryby wyświetlania:

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

Interfejs nawigacji jest narysowany przed powierzchnią NavigationSuiteScaffold. Wartości domyślne kolorów interfejsu podaje NavigationSuiteDefaults.colors(), ale możesz je też zastąpić. Jeśli np. tło paska nawigacyjnego ma być przezroczyste, ale pozostałe wartości mają pozostać domyślne, zastąp navigationBarContainerColor:

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

W ostatecznym rozrachunku można dostosować każdy element w interfejsie nawigacji. Wywołując funkcję item, możesz przekazać instancję NavigationSuiteItemColors. Klasa określa kolory elementów paska nawigacyjnego, kolumnie nawigacyjnej i szuflady nawigacyjnej. Oznacza to, że każdy typ interfejsu nawigacji może mieć identyczne kolory lub kolory w zależności od potrzeb. Zdefiniuj kolory na poziomie NavigationSuiteScaffold, aby używać tej samej instancji obiektu dla wszystkich elementów, i wywołaj funkcję NavigationSuiteDefaults.itemColors(), aby zastąpić tylko te, które chcesz zmienić:

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

Dostosuj typy nawigacji

Domyślne zachowanie NavigationSuiteScaffold zmienia interfejs nawigacji na podstawie klas rozmiaru okna. Możesz jednak zastąpić to działanie. Jeśli na przykład aplikacja wyświetla jeden duży panel treści w kanale, może używać stałej szuflady nawigacji po rozwiniętych oknach, ale może wrócić do domyślnego działania w przypadku klas kompaktowych i średnich:

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

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

Dodatkowe materiały

Zobacz wskazówki dotyczące stylu Material Design:

Zobacz te komponenty biblioteki androidx.compose.material3: