Crea un layout per i riquadri di supporto

Il layout del riquadro di supporto consente all'utente di concentrarsi sui contenuti principali dell'app e allo stesso tempo di visualizzare 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 del Materiale 3.

Implementa un riquadro di supporto con NavigableSupportingPaneScaffold

NavigableSupportingPaneScaffold è un composable che semplifica l'implementazione di un layout del riquadro di supporto in Jetpack Compose. Avvolge SupportingPaneScaffold e aggiunge la navigazione integrata e la gestione del pulsante Indietro predittiva.

Una struttura a riquadri di supporto supporta fino a tre riquadri:

  • Riquadro principale: mostra i contenuti principali.
  • Riquadro di supporto: fornisce contesto aggiuntivo o strumenti correlati al riquadro principale.
  • Riquadro aggiuntivo (facoltativo): utilizzato per i contenuti supplementari, se necessario.

La struttura si adatta in base alle dimensioni della finestra:

  • Nelle finestre di grandi dimensioni, 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.

    Contenuti principali che occupano la maggior parte dello spazio di visualizzazione con contenuti di supporto a lato.
    Figura 1. Supporto del layout del riquadro.

Aggiungi le dipendenze

NavigableSupportingPaneScaffold fa parte della libreria di layout adattivo Material 3.

Aggiungi le tre dipendenze correlate seguenti 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")

Groovy

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 HingeInfo e Posture
  • adaptive-layout: layout adattivi come ListDetailPaneScaffold e SupportingPaneScaffold
  • adaptive-navigation: composabili per la navigazione all'interno e tra riquadri, nonché layout adattivi che supportano la navigazione per impostazione predefinita, come NavigableListDetailPaneScaffold e NavigableSupportingPaneScaffold

Assicurati che il progetto includa compose-material3-adaptive versione 1.1.0-beta1 o successive.

Attivare il gesto Indietro predittivo

Per attivare le animazioni Indietro predittive in Android 15 o versioni precedenti, devi attivare il supporto del gesto Indietro predittivo. Per attivare la funzionalità, aggiungi android:enableOnBackInvokedCallback="true" al tag <application> o 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, il pulsante Indietro predittivo è attivo per impostazione predefinita.

Creare un navigatore

Nelle finestre piccole viene visualizzato un solo riquadro alla volta, quindi utilizza ThreePaneScaffoldNavigator per spostarti tra i riquadri. Crea un'istanza del navigatore con rememberSupportingPaneScaffoldNavigator.

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

Passare il navigatore allo scafo

Lo scafo richiede un ThreePaneScaffoldNavigator, ovvero un'interfaccia che rappresenta lo stato dello scafo, ThreePaneScaffoldValue e un PaneScaffoldDirective.

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = { /*...*/ },
    supportingPane = { /*...*/ },
)

Il riquadro principale e quello di supporto sono composabili contenenti i tuoi contenuti. Utilizza AnimatedPane per applicare le animazioni dei riquadri predefinite durante la navigazione. Utilizza il valore dello scafo per verificare se il riquadro di supporto è nascosto. In questo caso, mostra un pulsante che chiama navigateTo(SupportingPaneScaffoldRole.Supporting) per visualizzare il riquadro di supporto.

Ecco un'implementazione completa dello scafo:

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

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()) {
            Text("Supporting pane")
        }
    }
)

Componenti composibili del riquadro Estrazione

Estrai i singoli riquadri di un SupportingPaneScaffold nei rispettivi composabili per renderli riutilizzabili e verificabili. Usa 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(
    modifier: Modifier = Modifier,
) {
    AnimatedPane(modifier = modifier.safeContentPadding()) {
        // Supporting pane content
        Text("This is the supporting pane")
    }
}

L'estrazione dei riquadri in componenti composibili semplifica l'utilizzo di SupportingPaneScaffold (confronta quanto segue con l'implementazione completa della struttura 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() },
)

Se hai bisogno di un maggiore controllo su aspetti specifici della struttura, valuta la possibilità di utilizzare SupportingPaneScaffold anziché NavigableSupportingPaneScaffold. Questo accetta PaneScaffoldDirective e ThreePaneScaffoldValue o ThreePaneScaffoldState separatamente. Questa flessibilità ti consente di implementare la logica personalizzata per la spaziatura dei riquadri e di determinare quanti riquadri devono essere visualizzati contemporaneamente. Puoi anche attivare il supporto del tasto Indietro predittivo aggiungendo ThreePaneScaffoldPredictiveBackHandler.

Aggiungi ThreePaneScaffoldPredictiveBackHandler

Collega il gestore Indietro predittivo che prende un'istanza di navigatore di struttura e specifica backBehavior. Questo determina in che modo le destinazioni vengono rimosse dalla pila precedente 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 principali e di supporto in SupportingPaneScaffold. Utilizza AnimatedPane per le animazioni dei riquadri predefinite.

Dopo aver implementato questi passaggi, il codice dovrebbe avere il seguente aspetto:

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