Tworzenie układu ze szczegółami listy

Szczegóły listy to wzorzec interfejsu składający się z układu z 2 panelami, w którym jeden z nich zawiera listę elementów, a drugi – szczegóły elementów wybranych z listy.

Ten wzór jest szczególnie przydatny w przypadku aplikacji, które dostarczają szczegółowych informacji o elementach dużych kolekcji, np. klienta poczty e-mail z listą e-maili i szczegółowymi treściami każdego e-maila. Lista z szczegółami może być też używana na mniej istotnych ścieżkach, np. do podziału preferencji aplikacji na listę kategorii z preferencjami dla każdej kategorii w panelu szczegółów.

Zaimplementuj wzorzec interfejsu za pomocą interfejsu ListDetailPaneScaffold

ListDetailPaneScaffold to komponent, który upraszcza implementację w aplikacji wzorca listy i szczegółów. Szkielet listy i szczegółów może składać się z maksymalnie 3 paneli: panelu listy, panelu szczegółów i opcjonalnego dodatkowego panelu. Szkielet obsługuje obliczenia dotyczące miejsca na ekranie. Jeśli rozmiar ekranu jest wystarczający, panel szczegółów jest wyświetlany obok panelu listy. Na małych ekranach rusztowanie automatycznie przełącza się na pełny ekran, na którym wyświetla się lista lub okienko szczegółów.

Panel z informacjami wyświetlany obok strony listy.
Rysunek 1. Jeśli rozmiar ekranu jest wystarczający, panel szczegółowy jest wyświetlany obok panelu listy.
Po wybraniu elementu panel szczegółów zajmuje cały ekran.
Rysunek 2. Gdy rozmiar ekranu jest ograniczony, panel szczegółów (po wybraniu elementu) zajmuje całą przestrzeń.

Deklarowanie zależności

ListDetailPaneScaffold należy do biblioteki Material 3 z dopasowywaniem układu.

Dodaj do pliku build.gradle aplikacji lub modułu te 3 powiązane zależności:

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 – elementy składowe niskiego poziomu, takie jak HingeInfo i Posture.
  • adaptive-layout – układy adaptacyjne, takie jak ListDetailPaneScaffold i SupportingPaneScaffold
  • adaptive-navigation – komponenty do nawigacji w obrębie paneli i między nimi

Podstawowe użycie

Wdróż ListDetailPaneScaffold w ten sposób:

  1. Użyj zajęć, które odpowiadają treściom, które chcesz wybrać. Aby umożliwić zapisywanie i przywracanie wybranego elementu listy, ta klasa powinna mieć wartość Parcelable. Użyj wtyczki kotlin-parcelize, aby wygenerować kod.

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

  2. Utwórz ThreePaneScaffoldNavigator za pomocą rememberListDetailPaneScaffoldNavigator i dodaj BackHandler. Ten nawigator służy do przechodzenia między listą, panelem szczegółów i dodatkowymi panelami. Po zadeklarowaniu typu ogólnego, nawigator śledzi również stan rusztowania (czyli wyświetlany jest MyItem). Ponieważ ten typ można spakować, nawigator może zapisać i przywrócić stan, aby automatycznie obsługiwać zmiany konfiguracji. BackHandler umożliwia nawigację wstecz za pomocą systemowego gestu lub przycisku Wstecz. Oczekiwane działanie przycisku Wstecz w ListDetailPaneScaffold zależy od rozmiaru okna i bieżącej wartości szablonu. Jeśli ListDetailPaneScaffold obsługuje cofanie się z bieżącym stanem, canNavigateBack() ma wartość true, co włącza BackHandler.

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

  3. Przekazuj wartość scaffoldState z komponentu navigator do komponentu ListDetailPaneScaffold.

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

  4. Przekaż implementację panelu list do ListDetailPaneScaffold. UżyjAnimatedPane, aby zastosować domyślne animacje paneli podczas nawigacji. Następnie użyj polecenia 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. Dołącz wdrożenie panelu szczegółów w narzędziu ListDetailPaneScaffold. Po zakończeniu nawigacji currentDestination zawiera panel, do którego nawigowała aplikacja, w tym treści wyświetlane w tym panelu. Właściwość content ma ten sam typ, który został określony w pierwotnym wywołaniu funkcji remember (w tym przykładzie jest to MyItem), więc możesz też uzyskać do niej dostęp, aby wyświetlić dowolne dane.

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

Po wykonaniu powyższych czynności Twój kod powinien wyglądać mniej więcej tak:

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