Il layout del riquadro di supporto mantiene l'attenzione dell'utente sui contenuti principali dell'app, visualizzando al contempo informazioni di supporto pertinenti. Ad esempio, il riquadro principale potrebbe mostrare i dettagli di un film, mentre il riquadro di supporto elenca film simili, film dello stesso regista o opere con gli stessi attori.
Per maggiori dettagli, consulta le linee guida per il riquadro di supporto di Material 3.
Implementa un riquadro di supporto con uno scaffold
NavigableSupportingPaneScaffold è un componibile che semplifica l'implementazione di un layout del riquadro di supporto in Jetpack Compose. Aggrega SupportingPaneScaffold e aggiunge la navigazione integrata e la gestione della funzionalità Indietro predittivo.
Un'impalcatura del riquadro di supporto supporta fino a tre riquadri:
- Riquadro principale: mostra i contenuti principali.
- Riquadro di supporto: fornisce contesto o strumenti aggiuntivi correlati al riquadro principale.
- Riquadro aggiuntivo (facoltativo): utilizzato per contenuti supplementari, se necessario.
Lo scaffold si adatta in base alle dimensioni della finestra:
- Nelle finestre grandi, i riquadri principale e di supporto vengono visualizzati uno accanto all'altro.
Nelle finestre piccole, è visibile un solo riquadro alla volta, che cambia man mano che gli utenti navigano.
Figura 1. Layout del riquadro di supporto.
Aggiungi dipendenze
NavigableSupportingPaneScaffold fa parte della libreria di layout adattivi di Material 3.
Aggiungi le seguenti tre dipendenze correlate al file build.gradle della tua app o del tuo modulo:
Kotlin
implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")
Alla moda
implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
adaptive: componenti di base di basso livello come
HingeInfoePostureadaptive-layout: layout adattivi come
ListDetailPaneScaffoldeSupportingPaneScaffoldadaptive-navigation: componibili per la navigazione all'interno e tra i riquadri, nonché layout adattivi che supportano la navigazione per impostazione predefinita, come
NavigableListDetailPaneScaffoldeNavigableSupportingPaneScaffold
Verifica che il progetto includa compose-material3-adaptive versione 1.1.0-beta1 o successive.
Attiva il gesto Indietro predittivo
Per attivare le animazioni di Indietro predittivo in Android 15 o versioni precedenti, devi attivare il supporto del gesto Indietro predittivo. Per attivare questa funzionalità, aggiungi android:enableOnBackInvokedCallback="true" al tag <application> o ai singoli tag <activity> all'interno del file AndroidManifest.xml.
Se la tua app ha come target Android 16 (livello API 36) o versioni successive, la funzionalità Indietro predittivo è attivata per impostazione predefinita.
Crea un navigatore
Nelle finestre piccole, viene visualizzato un solo riquadro alla volta, quindi utilizza un ThreePaneScaffoldNavigator per spostarti da un riquadro all'altro. Crea un'istanza
del navigatore con rememberSupportingPaneScaffoldNavigator.
val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator() val scope = rememberCoroutineScope()
Passa il navigatore allo scaffold
Lo scaffold richiede un ThreePaneScaffoldNavigator, ovvero un'interfaccia che rappresenta lo stato dello scaffold, ThreePaneScaffoldValue e un PaneScaffoldDirective.
NavigableSupportingPaneScaffold( navigator = scaffoldNavigator, mainPane = { /*...*/ }, supportingPane = { /*...*/ }, )
Il riquadro principale e il riquadro di supporto sono elementi componibili che contengono i tuoi contenuti. Utilizza AnimatedPane per applicare le animazioni predefinite dei riquadri durante la navigazione. Utilizza il valore dello scaffold per verificare se il riquadro di supporto è nascosto. In questo caso, visualizza un pulsante che chiama navigateTo(SupportingPaneScaffoldRole.Supporting) per visualizzare il riquadro di supporto.
Per gli schermi di grandi dimensioni, utilizza il metodo ThreePaneScaffoldNavigator.navigateBack() per chiudere il riquadro di supporto, passando la costante BackNavigationBehavior.PopUntilScaffoldValueChange. La chiamata di questo metodo forza una ricomposizione di NavigableSupportingPaneScaffold.
Durante la ricomposizione, controlla la proprietà ThreePaneScaffoldNavigator.currentDestination per determinare se mostrare il riquadro di supporto.
Ecco un'implementazione completa dello scaffold:
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") } } } )
Estrai gli elementi componibili dei riquadri
Estrai i singoli riquadri di un SupportingPaneScaffold nei rispettivi elementi componibili per renderli riutilizzabili e testabili. Utilizza ThreePaneScaffoldScope per accedere a AnimatedPane se vuoi le animazioni predefinite:
@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") } } }
L'estrazione dei riquadri in elementi componibili semplifica l'utilizzo di
SupportingPaneScaffold (confronta quanto segue con l'implementazione completa
dello scaffold nella sezione precedente):
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) }, )
Se hai bisogno di un maggiore controllo su aspetti specifici dello scaffold, valuta l'utilizzo di SupportingPaneScaffold anziché di NavigableSupportingPaneScaffold. Questo accetta un PaneScaffoldDirective e ThreePaneScaffoldValue o ThreePaneScaffoldState separatamente. Questa flessibilità ti consente di implementare
una logica personalizzata per la spaziatura dei riquadri e di determinare quanti riquadri devono essere visualizzati
contemporaneamente. Puoi anche attivare il supporto di Indietro predittivo aggiungendo
ThreePaneScaffoldPredictiveBackHandler.
Aggiungi ThreePaneScaffoldPredictiveBackHandler
Collega il gestore di Indietro predittivo che accetta un'istanza di ScaffoldNavigator e specifica backBehavior. Determina il modo in cui le destinazioni vengono rimosse dal backstack durante la navigazione a ritroso. Poi passa scaffoldDirective e scaffoldState a SupportingPaneScaffold. Utilizza l'overload che accetta un
ThreePaneScaffoldState, passando scaffoldNavigator.scaffoldState.
Definisci i riquadri principale e di supporto all'interno di SupportingPaneScaffold. Utilizza AnimatedPane per le animazioni predefinite dei riquadri.
Dopo aver implementato questi passaggi, il codice dovrebbe essere simile al seguente:
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) }, )