Crea un layout elenco-dettagli

Dettaglio elenco è un pattern di UI costituito da un layout a due riquadri 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 su elementi di grandi raccolte, ad esempio un client di posta che contiene un elenco di email e i contenuti dettagliati di ciascun messaggio. L'elenco dettagliato può essere utilizzato anche per percorsi meno critici come la divisione dell'app preferenze in un elenco di categorie con le preferenze per ogni categoria in nel riquadro dei dettagli.

Implementare il pattern dell'interfaccia utente con ListDetailPaneScaffold

ListDetailPaneScaffold è un componente composable che semplifica l'implementazione del pattern elenco-dettagli nella tua app. Uno scafo elenco-dettagli può essere composto da un massimo di tre riquadri: un riquadro elenco, un riquadro dei dettagli e un riquadro aggiuntivo facoltativo. La lo scaffold gestisce i calcoli dello spazio sullo schermo. Se le dimensioni dello schermo sono sufficientemente grandi, il riquadro dei dettagli viene visualizzato accanto al riquadro dell'elenco. Su schermi di piccole dimensioni, la struttura 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 un elemento è stato selezionato). occupa tutto lo spazio.

Dichiara le dipendenze

ListDetailPaneScaffold 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'
  • Adattiva: componenti di base di basso livello come HingeInfo e Posture
  • adaptive-layout: layout adattivi come ListDetailPaneScaffold e SupportingPaneScaffold
  • navigazione adattiva: elementi componibili per la navigazione all'interno di tra i riquadri

Utilizzo di base

Implementa ListDetailPaneScaffold come segue:

  1. Utilizza una classe che rappresenti i contenuti da selezionare. Questa classe 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 per te.

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

  2. Crea una ThreePaneScaffoldNavigator con rememberListDetailPaneScaffoldNavigator e aggiungi BackHandler. Questo il navigatore viene utilizzato per spostarsi tra l'elenco, i dettagli e i riquadri aggiuntivi. Di dichiarando un tipo generico, il navigatore monitora anche lo stato del scaffold (ovvero, MyItem viene visualizzato). Poiché questo tipo è "parcelable", lo stato può essere salvato e ripristinato dal navigatore per e gestire automaticamente le modifiche alla configurazione. BackHandler supporta la navigazione a ritroso 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 attuale dell'armatura. Se ListDetailPaneScaffold è in grado di supportare il recupero attuale, il valore canNavigateBack() è true e viene attivato BackHandler.

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

  3. Passa il scaffoldState dal navigator al ListDetailPaneScaffold componibile.

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

  4. Fornisci l'implementazione del riquadro degli elenchi al ListDetailPaneScaffold. Utilizza AnimatedPane per applicare le animazioni dei riquadri predefinite durante la navigazione. Quindi utilizza ThreePaneScaffoldNavigator per accedere al riquadro dei dettagli, ListDetailPaneScaffoldRole.Detail e visualizza 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 è arrivata l'app, inclusi i contenuti visualizzati nel riquadro. La proprietà content è dello stesso tipo specificato nella chiamata remember originale (MyItem in questo esempio), quindi puoi anche accedere alla proprietà 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)
            }
        }
    },
)