Crea un layout elenco-dettagli

List-detail è un pattern UI costituito da un layout a due riquadri, in cui un riquadro presenta un elenco di elementi e un altro riquadro visualizza 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 che ha un elenco di email e i contenuti dettagliati di ogni messaggio email. L'attributo elenco dettaglio può essere utilizzato anche per percorsi meno critici, come la suddivisione delle preferenze delle app in un elenco di categorie con le preferenze per ogni categoria nel riquadro dei dettagli.

Implementa pattern UI con ListDetailPaneScaffold

ListDetailPaneScaffold è un componibile che semplifica l'implementazione del pattern elenco-dettagli nella tua app. Uno scaffold elenco-dettaglio può essere composto da fino a tre riquadri: un riquadro dell'elenco, un riquadro dei dettagli e un riquadro aggiuntivo facoltativo. Lo scaffold gestisce i calcoli dello spazio sullo schermo. Quando le dimensioni dello schermo sono sufficienti, il riquadro dei dettagli viene visualizzato accanto al riquadro dell'elenco. Su schermi di piccole dimensioni, lo scaffold passa automaticamente alla visualizzazione dell'elenco o del riquadro dei dettagli a schermo intero.

Un riquadro dei dettagli visualizzato accanto alla pagina dell'elenco.
Figura 1. Quando sono disponibili dimensioni dello schermo 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 (poiché un elemento è stato selezionato) occupa tutto lo spazio.

Dichiara le dipendenze

ListDetailPaneScaffold fa parte della libreria di layout adattivi di Material 3.

La tua app deve includere dipendenze per tre librerie Material 3 correlate:

  • Adattiva: componenti di base di basso livello come HingeInfo e Posture
  • Layout adattivo: layout adattivi come ListDetailPaneScaffold e SupportingPaneScaffold
    • Navigazione adattiva: elementi componibili per la navigazione all'interno e tra i riquadri

Aggiungi le dipendenze al file build.gradle della tua app o del tuo modulo:

Kotlin


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

Alla moda


implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha12'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha12'

Utilizzo di base

Implementa ListDetailPaneScaffold nel seguente modo:

  1. Utilizza una classe che rappresenti i contenuti da selezionare. Questo corso deve essere Parcelable per supportare il salvataggio e il ripristino dell'elemento dell'elenco selezionato. Utilizza il plug-in kotlin-parcelize per generare il codice automaticamente.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. Crea un ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator e aggiungi un BackHandler. Questo navigatore viene utilizzato per spostarsi tra l'elenco, i dettagli e i riquadri aggiuntivi. Se dichiara un tipo generico, il navigatore monitora anche lo stato dello scaffold, ovvero quello che viene visualizzato da MyItem. Poiché questo tipo è parcelabile, lo stato può essere salvato e ripristinato dal navigatore per gestire automaticamente le modifiche alla configurazione. BackHandler supporta la navigazione indietro utilizzando il gesto o il pulsante Indietro di sistema. Il comportamento previsto del pulsante Indietro per un ListDetailPaneScaffold dipende dalle dimensioni della finestra e dal valore dello scaffold attuale. Se ListDetailPaneScaffold è in grado di supportare il ripristino dello stato attuale, il valore di canNavigateBack() è true e consente di attivare BackHandler.

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

  3. Passa il scaffoldState da navigator al componibile ListDetailPaneScaffold.

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

  4. Fornisci l'implementazione del riquadro elenco a ListDetailPaneScaffold. Utilizza AnimatedPane per applicare le animazioni predefinite del riquadro durante la navigazione. Poi usa ThreePaneScaffoldNavigator per accedere al riquadro dei dettagli ListDetailPaneScaffoldRole.Detail e visualizzare l'elemento passato.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. Includi l'implementazione del riquadro dei dettagli in ListDetailPaneScaffold. Al termine della navigazione, currentDestination contiene il riquadro a cui è stata visitata la tua app, inclusi i contenuti visualizzati al suo interno. La proprietà content è dello stesso tipo specificato nella chiamata di memorizzazione originale (MyItem in questo esempio), quindi puoi accedere alla proprietà anche per tutti i dati che devi visualizzare.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

Dopo aver implementato i passaggi precedenti, il codice dovrebbe essere simile al seguente:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

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

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)