Tworzenie układu ze szczegółami listy

Szczegóły listy to wzorzec interfejsu użytkownika składający się z układu z 2 panelami, w którym jeden panel zawiera listę elementów, a inny zawiera szczegółowe informacje o elementach wybranych z listy.

Wzorzec jest szczególnie przydatny w aplikacjach, które dostarczają szczegółowe informacje o elementach dużych zbiorów, takich jak klient poczty e-mail z listą e-maili i szczegółową treścią każdej wiadomości. Szczegóły listy mogą być też używane w przypadku mniej ważnych ścieżek, na przykład do dzielenia ustawień aplikacji na listę kategorii z preferencjami każdej kategorii w panelu szczegółów.

Zaimplementuj wzorzec interfejsu za pomocą funkcji ListDetailPaneScaffold

ListDetailPaneScaffold to funkcja kompozycyjna, która upraszcza implementację wzorca szczegółów listy w aplikacji. Szkielet szczegółów listy może się składać z maksymalnie 3 paneli: panelu listy, panelu szczegółów i opcjonalnego panelu dodatkowego. Platforma obsługuje obliczenia przestrzeni ekranu. Gdy dostępny jest wystarczający rozmiar ekranu, obok panelu z listą wyświetla się panel szczegółów. Na małych ekranach system automatycznie przełącza się na pełny ekran z listą lub panelem szczegółów.

Okienko szczegółów widoczne obok strony z listą.
Rysunek 1. Gdy dostępna będzie wystarczająca ilość ekranu, panel szczegółów pojawi się obok panelu listy.
Po wybraniu elementu okienko szczegółów zajmuje cały ekran.
Rysunek 2. Przy ograniczonym rozmiarze ekranu okienko szczegółów (ponieważ został wybrany element) zajmuje całą przestrzeń.

Deklarowanie zależności

ListDetailPaneScaffold jest częścią biblioteki układu adaptacyjnego Material 3.

Aplikacja musi zawierać zależności od 3 powiązanych bibliotek Material 3:

  • adaptacyjne – elementy składowe niskiego poziomu, takie jak HingeInfo i Posture.
  • adapttive-layout – adaptacyjne układy, np. ListDetailPaneScaffold i SupportingPaneScaffold
    • nawigacja adaptacyjna – elementy kompozycyjne umożliwiające nawigację w panelach i między nimi.

Dodaj zależności do pliku build.gradle aplikacji lub modułu:

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

Odlotowy


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'

Podstawowe użycie

Wdróż ListDetailPaneScaffold w ten sposób:

  1. Użyj klasy, która reprezentuje treść, którą chcesz wybrać. Ta klasa powinna mieć typ Parcelable, aby umożliwić zapisywanie i przywracanie wybranego elementu listy. Użyj wtyczki kotlin-parcelize, aby wygenerować kod za Ciebie.

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

  2. Utwórz ThreePaneScaffoldNavigator z rememberListDetailPaneScaffoldNavigator i dodaj BackHandler. Służy on do poruszania się między listą, szczegółami i dodatkowymi panelami. Po zadeklarowaniu typu ogólnego nawigator śledzi również stan rusztowania (czyli pokazuje, który element MyItem jest wyświetlany). Ten typ można parować, więc nawigator może zapisać i przywrócić stan w celu automatycznej obsługi zmian w konfiguracji. BackHandler zapewnia obsługę przechodzenia wstecz za pomocą systemowego gestu lub przycisku Wstecz. Oczekiwane działanie przycisku Wstecz w przypadku elementu ListDetailPaneScaffold zależy od rozmiaru okna i bieżącej wartości rusztowania. Jeśli ListDetailPaneScaffold obsługuje przywrócenie obecnego stanu, canNavigateBack() ma wartość true, co powoduje włączenie BackHandler.

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

  3. Przekaż scaffoldState z funkcji navigator do funkcji kompozycyjnej ListDetailPaneScaffold.

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

  4. Prześlij implementację panelu listy do ListDetailPaneScaffold. Użyj AnimatedPane, aby zastosować domyślne animacje paneli podczas nawigacji. Następnie użyj funkcji ThreePaneScaffoldNavigator, aby przejść do panelu szczegółów (ListDetailPaneScaffoldRole.Detail) i wyświetlić przekazany element.

    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. Umieść implementację panelu szczegółów w ListDetailPaneScaffold. Po zakończeniu nawigacji pole currentDestination będzie zawierać panel, do którego przekierowała aplikacja, wraz z wyświetloną w nim treścią. Właściwość content jest tego samego typu, co określona w pierwotnym wywołaniu funkcji zapamiętania (w tym przykładzie MyItem), więc masz też dostęp do wszystkich danych, które chcesz wyświetlić.

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

Po wykonaniu powyższych czynności kod powinien wyglądać podobnie do tego:

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