„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, mit der die Implementierung des Listen-Detail-Musters in Ihrer App vereinfacht wird. Ein Listen-Detail-Gerüst 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 kleinen Bildschirmgrößen wird automatisch entweder die Liste oder der Detailbereich im Vollbildmodus angezeigt.
Abhängigkeiten deklarieren
ListDetailPaneScaffold
ist Teil der adaptiven Bibliothek von Material 3.
Fügen Sie in der Datei build.gradle
für Ihre App oder Ihr Modul eine Abhängigkeit für die Bibliothek hinzu:
implementation("androidx.compose.material3.adaptive:adaptive:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-alpha07")
implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-alpha07")
Grundlegende Verwendung
Im Folgenden wird die grundlegende Verwendung von ListDetailPaneScaffold
veranschaulicht:
Aktuell ausgewähltes Element aus der Liste in einer änderbaren Statusvariablen speichern: Die Variable enthält das Element, das im Detailbereich angezeigt werden soll. Normalerweise würden Sie das aktuell ausgewählte Element mit
null
initialisieren. Dies bedeutet, dass noch keine Auswahl getroffen wurde.class MyItem(val id: Int) { companion object { val Saver: Saver<MyItem?, Int> = Saver( { it?.id }, ::MyItem, ) } }
var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) { mutableStateOf(null) }
Erstellen Sie die
ThreePaneScaffoldNavigator
mitrememberListDetailPaneScaffoldNavigator
und fügen Sie eineBackHandler
hinzu. Dieser Navigator wird verwendet, um zwischen der Liste, den Details und zusätzlichen Bereichen zu wechseln und den Status für das Gerüst anzugeben. Das neueBackHandler
bietet Unterstützung, um über die Zurück-Touch-Geste oder die Schaltfläche „Zurück“ des Systems zurückzugehen. Das erwartete Verhalten der Schaltfläche „Zurück“ für eineListDetailPaneScaffold
hängt von der Fenstergröße und dem aktuellen Scaffold-Wert ab. Wenn dasListDetailPaneScaffold
die Zurückkehr zum aktuellen Status unterstützt, istcanNavigateBack()
der Werttrue
und aktiviertBackHandler
.val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() }
Übergeben Sie die
scaffoldState
aus dernavigator
, die Sie erstellt haben, an die zusammensetzbare FunktionListDetailPaneScaffold
.ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, // ... )
Stellen Sie Ihre Listenbereichsimplementierung der
ListDetailPaneScaffold
bereit. Die Implementierung muss ein Callback-Argument zum Erfassen des neu ausgewählten Elements enthalten. Wenn dieser Callback ausgelöst wird, aktualisieren Sie die StatusvariableselectedItem
und verwenden SieThreePaneScaffoldNavigator
, um den Detailbereich (ListDetailPaneScaffoldRole.Detail
) anzuzeigen.ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane(Modifier) { MyList( onItemClick = { id -> // Set current item selectedItem = id // Switch focus to detail pane navigator.navigateTo(ListDetailPaneScaffoldRole.Detail) } ) } }, // ... )
Fügen Sie die Implementierung des Detailbereichs in
ListDetailPaneScaffold
ein. Zeigt den Detailinhalt nur an, wennselectedItem
nicht null ist.ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = // ... detailPane = { AnimatedPane(Modifier) { selectedItem?.let { item -> MyDetails(item) } } }, )
Nach der Implementierung der oben genannten Schritte sollte Ihr Code in etwa so aussehen:
// Currently selected item var selectedItem: MyItem? by rememberSaveable(stateSaver = MyItem.Saver) { mutableStateOf(null) } // Create the ListDetailPaneScaffoldState val navigator = rememberListDetailPaneScaffoldNavigator<Nothing>() BackHandler(navigator.canNavigateBack()) { navigator.navigateBack() } ListDetailPaneScaffold( directive = navigator.scaffoldDirective, value = navigator.scaffoldValue, listPane = { AnimatedPane(Modifier) { MyList( onItemClick = { id -> // Set current item selectedItem = id // Display the detail pane navigator.navigateTo(ListDetailPaneScaffoldRole.Detail) }, ) } }, detailPane = { AnimatedPane(Modifier) { // Show the detail pane content if selected item is available selectedItem?.let { item -> MyDetails(item) } } }, )