Ein Listen-Detail-Layout erstellen

Die 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 Platz auf dem Bildschirm vorhanden ist, wird der Detail Bereich neben dem Listenbereich angezeigt.
Nachdem ein Element ausgewählt wurde, wird der Detailbereich auf dem gesamten Bildschirm angezeigt.
Abbildung 2. Wenn der Platz auf dem Bildschirm begrenzt ist, nimmt der Detailbereich (da ein Element ausgewählt wurde) den gesamten Platz ein.

Muster „Liste – Details“ mit NavigableListDetailPaneScaffold implementieren

NavigableListDetailPaneScaffold ist eine komponierbare Funktion, die die Implementierung einer 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-Gerüst unterstützt bis zu drei Bereiche:

  1. Listenbereich: Zeigt eine Sammlung von Elementen an.
  2. Detailbereich: Zeigt die Details eines ausgewählten Elements an.
  3. Zusätzlicher Bereich (optional): Bietet bei Bedarf zusätzlichen Kontext.

Das Gerüst wird an die Fenstergröße angepasst:

  • In großen Fenstern werden die Bereiche „Liste“ und „Details“ 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

Ihr Projekt muss die Version 1.1.0-beta1 oder höher von compose-material3-adaptive enthalten.

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 in der Datei AndroidManifest.xml dem Tag <application> oder einzelnen <activity> Tags android:enableOnBackInvokedCallback="true" 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“, „Details“ und „Zusätzlich“ wechseln. Durch die Deklaration eines generischen Typs verfolgt der Navigator auch den Status des Gerüsts (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 hat, einschließlich der Inhalte, die im Bereich angezeigt werden. Die Eigenschaft 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 die zugrunde liegende Layoutstruktur nicht, wenn der E‑Mail-Inhalt im Detailbereich geändert wird. Daher kann die App oder der aktuelle Navigationsgraph mit der Zurück-Taste 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 „Details“ 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.

Abbildung, die Änderungen des Navigationswerts in verschiedenen Layoutbereichen zeigt.
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 bedeutet das, dass sich die visuelle Anzeige des ausgewählten Bereichs ändert.

Verwenden Sie diese Option, wenn eine klare visuelle Anzeige 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
                        )

                    }
                }
            )
        }
    }