Układ panelu pomocniczego pozwala użytkownikowi skupić się na głównej treści aplikacji, a jednocześnie wyświetlać istotne informacje pomocnicze. Na przykład w głównym panelu mogą być wyświetlane szczegóły filmu, a w panelu pomocniczym – podobne filmy, filmy tego samego reżysera lub filmy z tymi samymi aktorami.
Więcej informacji znajdziesz w wytycznych dotyczących panelu pomocniczego Material 3.
Implementowanie panelu pomocniczego z użyciem szkieletu
NavigableSupportingPaneScaffold to funkcja kompozycyjna, która upraszcza implementację układu panelu pomocniczego w Jetpack Compose. Zawiera SupportingPaneScaffold oraz wbudowaną nawigację i predykcyjne obsługiwanie gestu wstecz.
Struktura panelu pomocniczego może zawierać maksymalnie 3 panele:
- Główny panel: wyświetla główną zawartość.
- Panel pomocniczy: zawiera dodatkowy kontekst lub narzędzia związane z panelem głównym.
- Dodatkowy panel (opcjonalny): używany w razie potrzeby do wyświetlania dodatkowych treści.
Szkielet dostosowuje się do rozmiaru okna:
- W przypadku dużych okien panele główny i pomocniczy wyświetlają się obok siebie.
W małych oknach widoczny jest tylko jeden panel naraz, który zmienia się w miarę poruszania się użytkowników.
Rysunek 1. Układ panelu pomocniczego.
Dodawanie zależności
NavigableSupportingPaneScaffold jest częścią biblioteki układów adaptacyjnych Material 3.
Dodaj do pliku build.gradle aplikacji lub modułu te 3 zależności:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Groovy
implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
adaptacyjne: elementy składowe niskiego poziomu, takie jak
HingeInfoiPosture;adaptive-layout: układy adaptacyjne, np.
ListDetailPaneScaffoldiSupportingPaneScaffoldadaptive-navigation: komponenty kompozycyjne do nawigacji w panelach i między nimi, a także układy adaptacyjne, które domyślnie obsługują nawigację, np.
NavigableListDetailPaneScaffoldiNavigableSupportingPaneScaffold.
Upewnij się, że projekt zawiera compose-material3-adaptive w wersji 1.1.0-beta1 lub nowszej.
Włączanie gestu przewidywanego przejścia wstecz
Aby włączyć animacje przewidywanego przejścia wstecz w Androidzie 15 lub starszym, musisz wyrazić zgodę na obsługę gestu przewidywanego przejścia wstecz. Aby wyrazić zgodę, dodaj
android:enableOnBackInvokedCallback="true" do tagu <application> lub do poszczególnych tagów <activity> w pliku AndroidManifest.xml.
Gdy aplikacja jest kierowana na Androida 16 (API na poziomie 36) lub nowszego, funkcja przewidywanego powrotu jest domyślnie włączona.
Tworzenie nawigatora
W małych oknach wyświetlany jest tylko jeden panel naraz, więc do przełączania się między panelami używaj ThreePaneScaffoldNavigator. Utwórz instancję nawigatora za pomocą funkcji rememberSupportingPaneScaffoldNavigator.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Przekaż nawigator do elementu Scaffold
Szkielet wymaga ThreePaneScaffoldNavigator, czyli interfejsu reprezentującego stan szkieletu, ThreePaneScaffoldValue i PaneScaffoldDirective.
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
Główny i pomocniczy panel to komponenty zawierające Twoje treści. Użyj
AnimatedPane, aby podczas nawigacji zastosować domyślne animacje panelu. Użyj wartości struktury, aby sprawdzić, czy panel pomocniczy jest ukryty. Jeśli tak, wyświetl przycisk, który wywołuje funkcję navigateTo(SupportingPaneScaffoldRole.Supporting), aby wyświetlić panel pomocniczy.
W przypadku dużych ekranów użyj metody ThreePaneScaffoldNavigator.navigateBack(), aby zamknąć panel pomocniczy, przekazując stałą BackNavigationBehavior.PopUntilScaffoldValueChange. Wywołanie tej metody wymusza ponowne skomponowanie elementu NavigableSupportingPaneScaffold.
Podczas ponownego komponowania sprawdzaj właściwość ThreePaneScaffoldNavigator.currentDestination, aby określić, czy wyświetlić panel pomocniczy.
Oto pełna implementacja szkieletu:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() val backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { AnimatedPane( modifier = Modifier .safeContentPadding() .background(Color.Red) ) { if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) { Button( modifier = Modifier .wrapContentSize(), onClick = { scope.launch { scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting) } } ) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } }, supportingPane = { AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = Modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } } )
Wyodrębnianie funkcji kompozycyjnych z panelu
Wyodrębnij poszczególne panele SupportingPaneScaffold do osobnych komponentów kompozycyjnych, aby można było ich używać ponownie i testować. Aby uzyskać dostęp do AnimatedPane, użyj ThreePaneScaffoldScope, jeśli chcesz używać domyślnych animacji:
@OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.MainPane( shouldShowSupportingPaneButton: Boolean, onNavigateToSupportingPane: () -> Unit, modifier: Modifier = Modifier, ) { AnimatedPane( modifier = modifier.safeContentPadding() ) { // Main pane content if (shouldShowSupportingPaneButton) { Button(onClick = onNavigateToSupportingPane) { Text("Show supporting pane") } } else { Text("Supporting pane is shown") } } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.SupportingPane( scaffoldNavigator: ThreePaneScaffoldNavigator<Any>, modifier: Modifier = Modifier, backNavigationBehavior: BackNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange, ) { val scope = rememberCoroutineScope() AnimatedPane(modifier = Modifier.safeContentPadding()) { Column { // Allow users to dismiss the supporting pane. Use back navigation to // hide an expanded supporting pane. if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Expanded) { // Material design principles promote the usage of a right-aligned // close (X) button. IconButton( modifier = modifier.align(Alignment.End).padding(16.dp), onClick = { scope.launch { scaffoldNavigator.navigateBack(backNavigationBehavior) } } ) { Icon(Icons.Default.Close, contentDescription = "Close") } } Text("Supporting pane") } } }
Wyodrębnienie paneli do funkcji kompozycyjnych upraszcza korzystanie z elementu
SupportingPaneScaffold (porównaj to z pełną implementacją
elementu Scaffold w poprzedniej sekcji):
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )
Jeśli chcesz mieć większą kontrolę nad konkretnymi aspektami szkieletu, użyj SupportingPaneScaffold zamiast NavigableSupportingPaneScaffold. Ta funkcja akceptuje oddzielnie wartości PaneScaffoldDirective i ThreePaneScaffoldValue lub ThreePaneScaffoldState. Ta elastyczność pozwala wdrożyć niestandardową logikę odstępów między panelami i określić, ile paneli ma być wyświetlanych jednocześnie. Możesz też włączyć obsługę przewidywanego powrotu, dodając
ThreePaneScaffoldPredictiveBackHandler.
Dodaj ThreePaneScaffoldPredictiveBackHandler
Dołącz moduł obsługi przewidywanego przejścia wstecz, który przyjmuje instancję nawigatora szkieletowego i określa backBehavior. Określa, jak miejsca docelowe są usuwane ze stosu wstecznego podczas nawigacji wstecznej. Następnie przesuń scaffoldDirective i scaffoldState do SupportingPaneScaffold. Użyj przeciążenia, które akceptuje
ThreePaneScaffoldState, przekazując scaffoldNavigator.scaffoldState.
Określ główne i pomocnicze panele w SupportingPaneScaffold. Użyj
AnimatedPane w przypadku domyślnych animacji paneli.
Po wykonaniu tych czynności kod powinien wyglądać podobnie do tego:
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope() ThreePaneScaffoldPredictiveBackHandler( navigator = scaffoldNavigator, backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange ) SupportingPaneScaffold( directive = scaffoldNavigator.scaffoldDirective, scaffoldState = scaffoldNavigator.scaffoldState, mainPane = { MainPane( shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden, onNavigateToSupportingPane = { scope.launch { scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary) } } ) }, supportingPane = { SupportingPane(scaffoldNavigator = scaffoldNavigator) }, )