Ein Listen-Detail-Layout erstellen

„List-Detail“ ist ein UI-Muster, das aus einem Zwei-Fenster-Layout besteht, wobei in einem Bereich eine Liste der Elemente und in einem anderen die Details der aus der Liste ausgewählten Elemente angezeigt werden.

Das Muster ist besonders nützlich für Anwendungen, die detaillierte Informationen über Elemente großer Sammlungen bereitstellen, z. B. ein E-Mail-Client, der eine Liste von E-Mails und den detaillierten Inhalt jeder E-Mail-Nachricht enthält. Die Listen-Detailansicht kann auch für weniger kritische Pfade verwendet werden, wie das Aufteilen der App-Einstellungen in eine Liste von Kategorien mit den Einstellungen für jede Kategorie im Detailbereich.

UI-Muster mit ListDetailPaneScaffold implementieren

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

Ein Detailbereich neben der Listenseite.
Abbildung 1: Wenn eine ausreichende Bildschirmgröße verfügbar ist, wird der Detailbereich neben dem Listenbereich angezeigt.
Nachdem ein Element ausgewählt wurde, erstreckt sich der Detailbereich auf den gesamten Bildschirm.
Abbildung 2. Bei einer eingeschränkten Bildschirmgröße nimmt der Detailbereich (seit der Auswahl eines Elements) den gesamten Bereich ein.

Abhängigkeiten deklarieren

ListDetailPaneScaffold ist Teil der Bibliothek für adaptives Layout von Material 3.

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

  • adaptiv – untergeordnete Bausteine wie HingeInfo und Posture
  • adaptive-layout: adaptive Layouts wie ListDetailPaneScaffold und SupportingPaneScaffold
    • adaptive-navigation: zusammensetzbare Funktionen 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")

Groovig


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 Verwendung

Implementieren Sie ListDetailPaneScaffold so:

  1. Verwenden Sie eine Klasse, die den auszuwählenden Inhalt darstellt. Diese Klasse sollte Parcelable sein, damit das ausgewählte Listenelement gespeichert und wiederhergestellt werden kann. Generieren Sie den Code mit dem Kotlin-Plug-in für Sie.

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

  2. Erstellen Sie ein ThreePaneScaffoldNavigator mit rememberListDetailPaneScaffoldNavigator und fügen Sie eine BackHandler hinzu. Dieser Navigator wird verwendet, um zwischen der Liste, den Details und zusätzlichen Bereichen zu wechseln. Wenn Sie einen generischen Typ deklarieren, wird im Navigationsmenü auch der Status des Gerüsts erfasst (also MyItem angezeigt). Da es sich um einen Parzellentyp handelt, kann der Status über die Navigation gespeichert und wiederhergestellt werden, um Konfigurationsänderungen automatisch zu verarbeiten. Mit dem BackHandler können Sie mithilfe der Zurück-Touch-Geste oder der Schaltfläche des Systems zurückspringen. Das erwartete Verhalten der Schaltfläche „Zurück“ für eine ListDetailPaneScaffold hängt von der Fenstergröße und dem aktuellen Gerüstwert ab. Wenn das ListDetailPaneScaffold die Zurücksetzung mit dem aktuellen Status unterstützt, ist canNavigateBack() den Wert true und aktiviert BackHandler.

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

  3. Übergeben Sie die scaffoldState aus dem navigator an die zusammensetzbare Funktion ListDetailPaneScaffold.

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

  4. Stellen Sie Ihre Listenbereichimplementierung dem ListDetailPaneScaffold bereit. Mit AnimatedPane können Sie die Animationen des Standardbereichs 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 Ihre Implementierung des Detailbereichs in ListDetailPaneScaffold ein. Wenn die Navigation abgeschlossen ist, enthält currentDestination den Bereich, zu dem Ihre App navigiert ist, einschließlich des darin angezeigten Inhalts. Das Attribut content ist derselbe Typ, der im ursprünglichen Erinnerungsaufruf angegeben wurde (in diesem Beispiel MyItem). Du kannst also auch für alle Daten darauf zugreifen, die angezeigt werden sollen.

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

Nachdem Sie die oben genannten Schritte implementiert haben, sollte Ihr Code wie folgt 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)
            }
        }
    },
)