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.

Wzorzec jest szczególnie przydatny w aplikacjach, które dostarczają szczegółowych informacji o elementach dużych kolekcji, np. w kliencie poczty e-mail z listą adresów e-mail i szczegółową treścią każdej z nich. Szczegółów listy można też używać w przypadku mniej istotnych ścieżek, takich jak podzielenie ustawień aplikacji na listę kategorii z ustawieniami każdej z nich w panelu szczegółów.

Zaimplementuj wzorzec interfejsu za pomocą interfejsu ListDetailPaneScaffold

ListDetailPaneScaffold to element kompozycyjny, który upraszcza implementację wzorca szczegółów listy w aplikacji. Rusztowanie szczegółów listy może się składać z maksymalnie 3 paneli: listy, panelu szczegółów i opcjonalnego panelu dodatkowego. Rusztowanie oblicza, co zajmuje miejsce na ekranie. Jeśli ekran jest dostępny, okienko szczegółów pojawi się obok okienka z listą. Na małych ekranach rusztowanie automatycznie przełącza się na pełny ekran, na którym wyświetla się lista lub okienko szczegółów.

Okienko szczegółów widoczne obok strony z listą.
Rysunek 1. Jeśli ekran jest dostępny, okienko szczegółów pojawi się obok okienka z listą.
Po wybraniu elementu panel szczegółów zajmie cały ekran.
Rys. 2. Gdy rozmiar ekranu jest ograniczony, okienko szczegółów (po wybraniu elementu) zajmuje cały obszar.

Deklarowanie zależności

ListDetailPaneScaffold należy do 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
  • Układ adaptacyjny – układy adaptacyjne, np. ListDetailPaneScaffold i SupportingPaneScaffold
    • adaptive-Navigation – elementy kompozycyjne służące do poruszania się 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")

Odlotowe


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 wykorzystanie

Wdróż ListDetailPaneScaffold w ten sposób:

  1. Użyj klasy, która reprezentuje treść do wyboru. 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 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 wyświetlany jest MyItem). Ponieważ jest to parcelable, stan może zostać zapisany i przywrócony przez nawigator, aby automatycznie obsługiwać zmiany konfiguracji. BackHandler umożliwia nawigację wstecz za pomocą systemowego gestu lub przycisku Wstecz. Oczekiwane działanie przycisku Wstecz w przypadku ListDetailPaneScaffold zależy od rozmiaru okna i bieżącej wartości rubryka. 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. Przekaż scaffoldState z funkcji navigator do funkcji kompozycyjnej ListDetailPaneScaffold.

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

  4. Udostępnij w narzędziu ListDetailPaneScaffold implementację panelu listy. Użyj narzędzia AnimatedPane, aby zastosować domyślne animacje panelu 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 przeszedła aplikacja, w tym jego zawartość. Typ właściwości content jest taki sam jak w pierwotnym wywołaniu zapamiętania (MyItem w tym przykładzie), więc masz także dostęp do usługi w przypadku wszystkich danych, które chcesz wyświetlić.

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

Po zaimplementowaniu powyższych kroków 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)
            }
        }
    },
)