Układ panelu pomocniczego sprawia, że użytkownik skupia się na głównej treści aplikacji, a jednocześnie wyświetla odpowiednie informacje pomocnicze. Na przykład w panelu głównym 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 za pomocą szkieletu
NavigableSupportingPaneScaffold to funkcja kompozycyjna, która upraszcza implementowanie układu panelu pomocniczego w Jetpack Compose. Zawiera ona
SupportingPaneScaffold i dodaje wbudowaną obsługę nawigacji i przewidywanego przejścia wstecz
handling.
Szkielet panelu pomocniczego obsługuje maksymalnie 3 panele:
- Panel główny: wyświetla podstawową treść.
- Panel pomocniczy: zawiera dodatkowy kontekst lub narzędzia związane z panelem głównym.
- Panel dodatkowy (opcjonalny): w razie potrzeby służy do wyświetlania dodatkowych treści.
Szkielet dostosowuje się do rozmiaru okna:
- W dużych oknach panel główny i panel pomocniczy są wyświetlane obok siebie.
W małych oknach widoczny jest tylko 1 panel, który zmienia się w miarę poruszania się użytkownika.
Rysunek 1. Układ panelu pomocniczego.
Dodawanie zależności
NavigableSupportingPaneScaffold jest częścią biblioteki układów adaptacyjnych Material 3.
Dodaj te 3 powiązane zależności do pliku build.gradle aplikacji lub modułu:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Dynamiczny
implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
adaptive: elementy składowe niskiego poziomu, takie jak
HingeInfoiPostureadaptive-layout: Układy adaptacyjne, takie jak
ListDetailPaneScaffoldiSupportingPaneScaffoldadaptive-navigation: funkcje kompozycyjne do nawigowania w obrębie paneli i między nimi, a także układy adaptacyjne, które domyślnie obsługują nawigację, takie jak
NavigableListDetailPaneScaffoldiNavigableSupportingPaneScaffold
Sprawdź, czy Twój projekt zawiera bibliotekę 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 włączyć obsługę gestu przewidywanego przejścia wstecz. Aby to zrobić, dodaj
android:enableOnBackInvokedCallback="true" do tagu <application> lub
poszczególnych <activity> tagów w pliku AndroidManifest.xml.
Gdy aplikacja będzie kierowana na Androida 16 (API na poziomie 36) lub nowszego, przewidywane przejście wstecz będzie domyślnie włączone.
Tworzenie nawigatora
W małych oknach wyświetlany jest tylko 1 panel, dlatego do przechodzenia między panelami używaj
ThreePaneScaffoldNavigator. Utwórz instancję
nawigatora za pomocą rememberSupportingPaneScaffoldNavigator.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Przekazywanie nawigatora do szkieletu
Szkielet wymaga ThreePaneScaffoldNavigator, czyli interfejsu
reprezentującego stan szkieletu, ThreePaneScaffoldValue i
PaneScaffoldDirective.
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
Panel główny i panel pomocniczy to funkcje kompozycyjne zawierające Twoje treści. Aby podczas nawigacji stosować domyślne animacje paneli, użyj
AnimatedPane. Użyj
wartości szkieletu, aby sprawdzić, czy panel pomocniczy jest ukryty. Jeśli tak,
wyświetl przycisk, który wywołuje
navigateTo(SupportingPaneScaffoldRole.Supporting), aby wyświetlić
panel pomocniczy.
W przypadku dużych ekranów użyj ThreePaneScaffoldNavigator.navigateBack()
metody do zamknięcia panelu pomocniczego, przekazując stałą
BackNavigationBehavior.PopUntilScaffoldValueChange. Wywołanie tej
metody wymusza ponowne komponowanie NavigableSupportingPaneScaffold.
Podczas ponownego komponowania sprawdź 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 paneli
Wyodrębnij poszczególne panele SupportingPaneScaffold do własnych funkcji kompozycyjnych, aby można było ich używać ponownie i testować. Jeśli chcesz używać domyślnych animacji, użyj ThreePaneScaffoldScope
, aby uzyskać dostęp do AnimatedPane:
@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 SupportingPaneScaffold (porównaj poniższy kod z pełną implementacją szkieletu 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 potrzebujesz większej kontroli nad określonymi aspektami szkieletu, rozważ użycie
SupportingPaneScaffold zamiast NavigableSupportingPaneScaffold. Ta funkcja
akceptuje oddzielnie PaneScaffoldDirective i ThreePaneScaffoldValue lub
ThreePaneScaffoldState. Ta elastyczność pozwala na implementowanie niestandardowej logiki odstępów między panelami i określanie, ile paneli ma być wyświetlanych jednocześnie. Możesz też włączyć obsługę przewidywanego przejścia wstecz, dodając ThreePaneScaffoldPredictiveBackHandler.
Dodawanie ThreePaneScaffoldPredictiveBackHandler
Dołącz obsługę przewidywanego przejścia wstecz, która przyjmuje instancję nawigatora szkieletu, i określ backBehavior. Określa to, jak miejsca docelowe są usuwane ze stosu wstecznego podczas przechodzenia wstecz. Następnie przekaż scaffoldDirective i scaffoldState do SupportingPaneScaffold. Użyj przeciążenia, które akceptuje ThreePaneScaffoldState, przekazując scaffoldNavigator.scaffoldState.
Zdefiniuj panel główny i panel pomocniczy w SupportingPaneScaffold. Aby używać domyślnych animacji paneli, użyj AnimatedPane.
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) }, )