Ein Listen-Detail-Layout erstellen

„Listen-Detailansicht“ ist ein UI-Muster, das aus einem Layout mit zwei Bereichen besteht. In einem Bereich wird eine Liste mit Elementen angezeigt und im anderen Bereich die Details der Elemente, die in der Liste ausgewählt wurden.

Das Muster ist besonders nützlich für Anwendungen, die detaillierte Informationen zu Elementen großer Sammlungen bieten, z. B. ein E‑Mail-Client mit einer Liste von E‑Mails und dem detaillierten Inhalt jeder E‑Mail-Nachricht. Die Listen-Detailansicht kann auch für weniger kritische Pfade verwendet werden, z. B. um App-Einstellungen in eine Liste von Kategorien zu unterteilen, wobei die Einstellungen für jede Kategorie im Detailbereich angezeigt werden.

Ein Detailbereich, der neben der Listenseite angezeigt wird.
Abbildung 1. Wenn genügend Bildschirmfläche verfügbar ist, wird der Detailbereich neben dem Listenbereich angezeigt.
Nachdem ein Element ausgewählt wurde, wird der Detailbereich auf dem gesamten Bildschirm angezeigt.
Abbildung 2 Wenn die Bildschirmfläche begrenzt ist, nimmt der Detailbereich (da ein Element ausgewählt wurde) den gesamten Platz ein.

Muster „Liste – Detail“ mit NavigableListDetailPaneScaffold implementieren

NavigableListDetailPaneScaffold ist eine komponierbare Funktion, die die Implementierung eines Layouts vom Typ „Listen-Detailansicht“ in Jetpack Compose vereinfacht. Es umschließt ListDetailPaneScaffold und fügt integrierte Navigation und Animationen für intelligente „Zurück“-Gesten hinzu.

Ein Listen-Detailansicht-Scaffold unterstützt bis zu drei Bereiche:

  1. Listenbereich: Hier wird eine Sammlung von Elementen angezeigt.
  2. Detailbereich: Hier werden die Details eines ausgewählten Elements angezeigt.
  3. Zusätzlicher Bereich (optional): Hier werden bei Bedarf zusätzliche Informationen angezeigt.

Das Scaffold wird an die Fenstergröße angepasst:

  • In großen Fenstern werden die Bereiche „Liste“ und „Detail“ nebeneinander angezeigt.
  • In kleinen Fenstern ist jeweils nur ein Bereich sichtbar. Die Bereiche werden gewechselt, wenn Nutzer navigieren.

Abhängigkeiten deklarieren

NavigableListDetailPaneScaffold ist Teil der adaptiven Navigationsbibliothek von Material 3.

Fügen Sie der Datei build.gradle Ihrer App oder Ihres Moduls die folgenden drei zugehörigen Abhängigkeiten hinzu:

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'
  • adaptive: Low-Level-Bausteine wie HingeInfo und Posture
  • adaptive-layout: Adaptive Layouts wie ListDetailPaneScaffold und SupportingPaneScaffold
  • adaptive-navigation: Composables für die Navigation innerhalb und zwischen Bereichen sowie adaptive Layouts, die standardmäßig Navigation unterstützen, z. B. NavigableListDetailPaneScaffold und NavigableSupportingPaneScaffold

Achten Sie darauf, dass Ihr Projekt die Version 1.1.0-beta1 oder höher von compose-material3-adaptive enthält.

Intelligente „Zurück“-Geste aktivieren

Wenn Sie Animationen für intelligente „Zurück“-Gesten in Android 15 oder niedriger aktivieren möchten, müssen Sie die Unterstützung für die intelligente „Zurück“-Geste aktivieren. Fügen Sie dazu android:enableOnBackInvokedCallback="true" dem <application> Tag oder einzelnen <activity> Tags in der Datei AndroidManifest.xml hinzu. Weitere Informationen finden Sie unter Intelligente „Zurück“-Geste aktivieren.

Wenn Ihre App auf Android 16 (API-Level 36) oder höher ausgerichtet ist, ist die intelligente „Zurück“-Geste standardmäßig aktiviert.

Grundlegende Nutzung

Implementieren Sie NavigableListDetailPaneScaffold so:

  1. Verwenden Sie eine Klasse, die den ausgewählten Inhalt darstellt. Verwenden Sie eine Parcelable Klasse, um das Speichern und Wiederherstellen des ausgewählten Listenelements zu unterstützen. Verwenden Sie das Kotlin-Parcelize-Plug-in, um den Code für Sie zu generieren.
  2. Erstellen Sie mit rememberListDetailPaneScaffoldNavigator einen ThreePaneScaffoldNavigator.

Mit diesem Navigator können Sie zwischen den Bereichen „Liste“, „Detail“ und „Zusätzlich“ wechseln. Durch Deklarieren eines generischen Typs verfolgt der Navigator auch den Status des Scaffolds (d. h., welches MyItem angezeigt wird). Da dieser Typ parcelable ist, kann der Status vom Navigator gespeichert und wiederhergestellt werden, um Konfigurationsänderungen automatisch zu verarbeiten.

  1. Übergeben Sie den Navigator an das Composable NavigableListDetailPaneScaffold.

  2. Geben Sie die Implementierung des Listenbereichs für NavigableListDetailPaneScaffold an. Verwenden Sie AnimatedPane, um die Standardanimationen für Bereiche während der Navigation anzuwenden. Verwenden Sie dann ThreePaneScaffoldNavigator, um zum Detailbereich ListDetailPaneScaffoldRole.Detail zu navigieren und das übergebene Element anzuzeigen.

  3. Fügen Sie die Implementierung des Detailbereichs in NavigableListDetailPaneScaffold ein.

Nach Abschluss der Navigation enthält currentDestination den Bereich, zu dem Ihre App navigiert ist, einschließlich der Inhalte, die im Bereich angezeigt werden. Die Property contentKey hat denselben Typ, der im ursprünglichen Aufruf angegeben wurde. So können Sie auf alle Daten zugreifen, die Sie anzeigen müssen.

  1. Optional können Sie das defaultBackBehavior in NavigableListDetailPaneScaffold ändern. Standardmäßig verwendet NavigableListDetailPaneScaffold PopUntilScaffoldValueChange für defaultBackBehavior.

Wenn Ihre App ein anderes Muster für die Rückwärtsnavigation erfordert, können Sie dieses Verhalten überschreiben, indem Sie eine andere Option für BackNavigationBehavior angeben.

Optionen für BackNavigationBehavior

Im folgenden Abschnitt wird das Beispiel einer E‑Mail-App mit einer Liste von E‑Mails in einem Bereich und einer Detailansicht im anderen Bereich verwendet.

Dieses Verhalten konzentriert sich auf Änderungen an der Gesamtstruktur des Layouts. Bei einer Konfiguration mit mehreren Bereichen ändert sich durch das Ändern des E‑Mail-Inhalts im Detailbereich nicht die zugrunde liegende Layoutstruktur. Daher kann die App oder der aktuelle Navigationsgraph mit dem Button „Zurück“ beendet werden, da es im aktuellen Kontext keine Layoutänderung gibt, zu der zurückgekehrt werden kann. Bei einem Layout mit einem Bereich werden durch Drücken der Zurück-Taste Inhaltsänderungen in der Detailansicht übersprungen und zur Listenansicht zurückgekehrt, da dies eine klare Layoutänderung darstellt.

Betrachten Sie hierzu folgende Beispiele:

  • Mehrere Bereiche:Sie sehen eine E‑Mail (Element 1) im Detailbereich. Wenn Sie auf eine andere E‑Mail (Element 2) klicken, wird der Detailbereich aktualisiert, aber die Bereiche „Liste“ und „Detail“ bleiben sichtbar. Durch Drücken der Zurück-Taste kann die App oder der aktuelle Navigationsfluss beendet werden.
  • Ein Bereich:Sie sehen Element 1 und dann Element 2. Wenn Sie die Zurück-Taste drücken, kehren Sie direkt zum Bereich mit der E‑Mail-Liste zurück.

Verwenden Sie diese Option, wenn Nutzer bei jeder Zurück-Aktion deutliche Layoutübergänge sehen sollen.

Änderung des Navigationswerts.
PopUntilContentChange

Bei diesem Verhalten wird der angezeigte Inhalt priorisiert. Wenn Sie Element 1 und dann Element 2 ansehen, wird durch Drücken der Zurück-Taste zu Element 1 zurückgekehrt, unabhängig vom Layout.

Betrachten Sie hierzu folgende Beispiele:

  • Mehrere Bereiche:Sie sehen Element 1 im Detailbereich und klicken dann in der Liste auf Element 2. Der Detailbereich wird aktualisiert. Durch Drücken der Zurück-Taste wird im Detailbereich wieder Element 1 angezeigt.
  • Ein Bereich:Dieselbe Inhaltsänderung erfolgt.

Verwenden Sie diese Option, wenn Nutzer erwarten, dass sie mit der Zurück-Aktion zum zuvor angesehenen Inhalt zurückkehren.

der Übergang zwischen zwei Detailbereichen
PopUntilCurrentDestinationChange

Bei diesem Verhalten wird der Back-Stack so lange entfernt, bis sich das aktuelle Navigationsziel ändert. Dies gilt gleichermaßen für Layouts mit einem und mehreren Bereichen.

Betrachten Sie hierzu folgende Beispiele:

Unabhängig davon, ob Sie sich in einem Layout mit einem oder mehreren Bereichen befinden, wird der Fokus durch Drücken der Zurück-Taste immer vom hervorgehobenen Navigationselement zum vorherigen Ziel verschoben. In unserer E‑Mail-App ändert sich dadurch die visuelle Darstellung des ausgewählten Bereichs.

Verwenden Sie diese Option, wenn eine klare visuelle Darstellung der aktuellen Navigation für die Nutzererfahrung entscheidend ist.

zwischen Detail- und Listenbereich wechseln
PopLatest

Mit dieser Option wird nur das letzte Ziel aus dem Back-Stack entfernt. Verwenden Sie diese Option für die Rückwärtsnavigation, ohne Zwischenzustände zu überspringen.

Nachdem Sie diese Schritte ausgeführt haben, sollte Ihr Code in etwa so aussehen:

NavigableListDetailPaneScaffold(
    navigator = navigator,
    listPane = {
        AnimatedPane {
            ListContent(
                words = sampleWords,
                selectionState = navigator.currentDestination?.contentKey?.let {
                    SelectionVisibilityState.ShowSelection(it)
                } ?: SelectionVisibilityState.NoSelection,
                onWordClick = { word ->
                    scope.launch {
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word)
                    }
                },
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout
            )
        }
    },
    detailPane = {
        AnimatedPane {
            DetailContent(
                definedWord = navigator.currentDestination?.contentKey,
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout,
                onClosePane = {
                    scope.launch {
                        navigator.navigateBack(
                            backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
                        )

                    }
                }
            )
        }
    }