Crea un layout elenco-dettagli

Elenco-dettaglio è un pattern UI costituito da un layout a doppio riquadro in cui un riquadro presenta un elenco di elementi e un altro riquadro mostra i dettagli degli elementi selezionati dall'elenco.

Il pattern è particolarmente utile per le applicazioni che forniscono informazioni approfondite sugli elementi di grandi raccolte, ad esempio un client di posta con un elenco di email e i contenuti dettagliati di ogni messaggio email. Il dettaglio dell'elenco può essere utilizzato anche per percorsi meno critici come suddividere le preferenze dell'app in un elenco di categorie con le preferenze per ogni categoria nel riquadro dei dettagli.

Implementa il pattern UI con ListDetailPaneScaffold

ListDetailPaneScaffold è un elemento componibile che semplifica l'implementazione del pattern dei dettagli dell'elenco nella tua app. Un'impalcatura dei dettagli dell'elenco può essere costituita da massimo tre riquadri: un riquadro elenco, un riquadro dei dettagli e un riquadro aggiuntivo facoltativo. che gestisce i calcoli dello spazio sullo schermo. Quando sono disponibili dimensioni dello schermo sufficienti, il riquadro dei dettagli viene visualizzato accanto al riquadro dell'elenco. Sugli schermi di piccole dimensioni, l'impalcatura passa automaticamente alla visualizzazione a schermo intero dell'elenco o del riquadro dei dettagli.

Un riquadro dei dettagli visualizzato accanto alla pagina dell'elenco.
Figura 1. Quando le dimensioni dello schermo sono sufficienti, il riquadro dei dettagli viene visualizzato accanto al riquadro dell'elenco.
Dopo aver selezionato un elemento, il riquadro dei dettagli occupa l'intero schermo.
Figura 2. Quando le dimensioni dello schermo sono limitate, il riquadro dei dettagli (dato che è stato selezionato un elemento) occupa l'intero spazio.

Dichiara le dipendenze

ListDetailPaneScaffold fa parte della libreria adattiva di Material 3. Aggiungi una dipendenza per la libreria nel file build.gradle per l'app o il modulo:

implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha07")

Utilizzo di base

Di seguito è illustrato l'utilizzo di base di ListDetailPaneScaffold:

  1. Archivia l'elemento attualmente selezionato dall'elenco in una variabile di stato modificabile. La variabile contiene l'elemento da visualizzare nel riquadro dei dettagli. In genere, potresti inizializzare l'elemento attualmente selezionato con null, per indicare che non è stata ancora effettuata alcuna selezione.

    class MyItem(val id: Int) {
        companion object {
            val Saver: Saver<MyItem?, Int> = Saver(
                { it?.id },
                ::MyItem,
            )
        }
    }

    var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) {
        mutableStateOf(null)
    }

  2. Crea il ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator e aggiungi un BackHandler. Questa barra di navigazione viene utilizzata per spostarti tra l'elenco, i dettagli e i riquadri aggiuntivi e fornire lo stato all'impalcatura. L'elemento BackHandler aggiunto consente di tornare indietro utilizzando il pulsante o il gesto Indietro del sistema. Il comportamento previsto del pulsante Indietro per un oggetto ListDetailPaneScaffold dipende dalla dimensione della finestra e dal valore di scaffold attuale. Se ListDetailPaneScaffold può supportare il ripristino dello stato corrente, canNavigateBack() sarà true, con l'attivazione di BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. Passa il scaffoldState dal navigator che hai creato al componibile ListDetailPaneScaffold.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. Fornisci l'implementazione del riquadro dell'elenco in ListDetailPaneScaffold. Assicurati che l'implementazione includa un argomento di callback per acquisire l'elemento appena selezionato. Quando viene attivato questo callback, aggiorna la variabile di stato selectedItem e utilizza ThreePaneScaffoldNavigator per visualizzare il riquadro dei dettagli (ListDetailPaneScaffoldRole.Detail).

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane(Modifier) {
                MyList(
                    onItemClick = { id ->
                        // Set current item
                        selectedItem = id
                        // Switch focus to detail pane
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
                    }
                )
            }
        },
        // ...
    )

  5. Includi l'implementazione del riquadro dei dettagli in ListDetailPaneScaffold. Visualizza il contenuto dei dettagli solo se selectedItem non è nullo.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane(Modifier) {
                selectedItem?.let { item ->
                    MyDetails(item)
                }
            }
        },
    )

Dopo aver implementato i passaggi precedenti, il codice dovrebbe avere un aspetto simile a questo:

// Currently selected item
var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) {
    mutableStateOf(null)
}

// Create the ListDetailPaneScaffoldState
val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane(Modifier) {
            MyList(
                onItemClick = { id ->
                    // Set current item
                    selectedItem = id
                    // Display the detail pane
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane(Modifier) {
            // Show the detail pane content if selected item is available
            selectedItem?.let { item ->
                MyDetails(item)
            }
        }
    },
)