Ein Listen-Detail-Layout erstellen

„List-Detail“ ist ein UI-Muster, das aus einem zweiteiligen Layout besteht, bei dem ein Bereich eine Liste von Elementen und ein anderer Bereich die Details der aus der Liste ausgewählten Elemente enthält.

Das Muster ist besonders nützlich für Anwendungen, die detaillierte Informationen über Elemente großer Sammlungen liefern, z. B. einen E-Mail-Client mit einer Liste von E-Mails und dem detaillierten Inhalt jeder E-Mail-Nachricht. Die Funktion „Listendetails“ kann auch für weniger wichtige Pfade verwendet werden. So lassen sich App-Einstellungen beispielsweise in eine Liste von Kategorien unterteilen, wobei die Einstellungen für jede Kategorie im Detailbereich angegeben sind.

UI-Muster mit ListDetailPaneScaffold implementieren

ListDetailPaneScaffold ist eine zusammensetzbare Funktion, die die Implementierung des Listen-Detail-Musters in Ihrer App vereinfacht. Ein Listen-Detail-Gerüst kann aus bis zu drei Bereichen bestehen: einem Listen-, einem Detail- und einem optionalen zusätzlichen Bereich. Das Gerüst übernimmt die Berechnung der Bildschirmfläche. Wenn eine ausreichende Bildschirmgröße verfügbar ist, wird der Detailbereich neben dem Listenbereich angezeigt. Bei kleineren Bildschirmen wechselt das Gerüst automatisch zur Listen- oder Detailansicht im Vollbildmodus.

Detailbereich neben der Listenseite
Abbildung 1. Wenn genügend Bildschirmgröße verfügbar ist, wird der Detailbereich neben dem Listenbereich angezeigt.
Nachdem ein Element ausgewählt wurde, nimmt der Detailbereich den gesamten Bildschirm ein.
Abbildung 2. Wenn die Bildschirmgröße begrenzt ist, nimmt der Detailbereich (da ein Element ausgewählt wurde) den gesamten Bereich ein.

Abhängigkeiten deklarieren

ListDetailPaneScaffold gehört zur Bibliothek für adaptives Layout von Material 3.

Ihre App muss Abhängigkeiten für drei verwandte Material 3-Bibliotheken enthalten:

  • adaptiv: Low-Level-Bausteine wie HingeInfo und Posture
  • adaptive-Layout – Adaptive Layouts wie ListDetailPaneScaffold und SupportingPaneScaffold
    • adaptive-navigation – Composables zum Navigieren in und zwischen Bereichen

Fügen Sie die Abhängigkeiten der Datei build.gradle Ihrer Anwendung oder Ihres Moduls hinzu:

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")

Cool


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'

Grundlegende Nutzung

Implementieren Sie ListDetailPaneScaffold so:

  1. Verwenden Sie eine Klasse, die den auszuwählenden Inhalt darstellt. Diese Klasse sollte Parcelable sein, um das Speichern und Wiederherstellen des ausgewählten Listenelements zu unterstützen. Verwenden Sie das Plug-in kötlin-parcelize, um den Code für Sie zu generieren.

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

  2. Erstelle eine ThreePaneScaffoldNavigator mit rememberListDetailPaneScaffoldNavigator und füge eine BackHandler hinzu. Mit diesem Navigator wechseln Sie zwischen der Liste, den Details und zusätzlichen Bereichen. Durch die Deklaration eines generischen Typs verfolgt der Navigator auch den Status des Gerüsts (d. h., MyItem wird angezeigt). Da dieser Typ geparst werden kann, kann der Status vom Navigator gespeichert und wiederhergestellt werden, um Konfigurationsänderungen automatisch zu verarbeiten. Der BackHandler bietet Unterstützung für die Zurück-Navigation mithilfe der Zurück-Touch-Geste oder Taste des Systems. Das erwartete Verhalten der Schaltfläche „Zurück“ für ein ListDetailPaneScaffold hängt von der Fenstergröße und dem aktuellen Gerüstwert ab. Wenn ListDetailPaneScaffold die Rückkehr mit dem aktuellen Status unterstützen kann, hat canNavigateBack() den Wert true. Dadurch wird BackHandler aktiviert.

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

  3. Übergeben Sie scaffoldState von navigator an die zusammensetzbare ListDetailPaneScaffold.

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

  4. Stellen Sie Ihre Listenbereich-Implementierung für den ListDetailPaneScaffold bereit. Mit AnimatedPane können Sie die Standardanimationen von Bereichen während der Navigation anwenden. Verwenden Sie dann ThreePaneScaffoldNavigator, um zum Detailbereich ListDetailPaneScaffoldRole.Detail zu wechseln und das übergebene Element aufzurufen.

    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. Fügen Sie die Implementierung des Detailbereichs in ListDetailPaneScaffold ein. Wenn die Navigation abgeschlossen ist, enthält currentDestination den Bereich, zu dem Ihre App navigiert hat, einschließlich des im Bereich angezeigten Inhalts. Das Attribut content ist derselbe Typ, der im ursprünglichen Aufruf zum Merken angegeben wurde (in diesem Beispiel MyItem). Sie können also auch für alle Daten auf das Attribut zugreifen, die angezeigt werden sollen.

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

Nachdem Sie die obigen Schritte implementiert haben, sollte Ihr Code in etwa so aussehen:

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