Tworzenie układu ze szczegółami listy

Lista z szczegółami to wzór interfejsu, który składa się z dwóch paneli. 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–szczegóły 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.

Panel szczegółów 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ń.

Implement the List-Detail Pattern with NavigableListDetailPaneScaffold

NavigableListDetailPaneScaffold to komponent, który upraszcza implementację układu listy z szczegółami w Jetpack Compose. Opisuje ona ListDetailPaneScaffold i dodaje wbudowaną nawigację oraz animacje przewidywanego przejścia wstecz.

Szkielet listy i szczegółów obsługuje maksymalnie 3 panele:

  1. Panel listy: wyświetla kolekcję elementów.
  2. Plik szczegółów: zawiera informacje o wybranym elemencie.
  3. Dodatkowy panel (opcjonalny): zawiera dodatkowy kontekst, gdy jest to potrzebne.

Szablon dostosowuje się do rozmiaru okna:

  • W dużych oknach panele listy i szczegółów są wyświetlane obok siebie.
  • W małych oknach widoczna jest tylko jedna karta, która zmienia się w miarę poruszania się użytkownika.

Deklarowanie zależności

NavigableListDetailPaneScaffold należy do biblioteki Material 3 z adaptacyjną nawigacją.

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, np. ListDetailPaneScaffoldSupportingPaneScaffold
  • adaptive-navigation: komponenty do nawigacji w obrębie paneli i między nimi, a także układy adaptacyjne, które domyślnie obsługują nawigację, takie jak NavigableListDetailPaneScaffold i NavigableSupportingPaneScaffold

Upewnij się, że projekt zawiera pakiet compose-material3-adaptive w wersji 1.1.0-beta1 lub nowszej.

Włączanie gestu przewidywanego przejścia wstecz

Aby włączyć animacje przewidywanego przejścia wstecz w Androidzie 15 lub starszym, musisz wyrazić zgodę na obsługę gestu przewidywanego przejścia wstecz. Aby włączyć tę funkcję, dodaj tag android:enableOnBackInvokedCallback="true" do tagu <application> lub do poszczególnych tagów <activity> w pliku AndroidManifest.xml. Więcej informacji znajdziesz w artykule Włączanie przewidującego gestu wstecz.

Gdy Twoja aplikacja jest kierowana na Androida 16 (poziom interfejsu API 36) lub nowszego, przewidywane cofnięcie jest domyślnie włączone.

Podstawowe użycie

Zaimplementuj dyrektywę NavigableListDetailPaneScaffold w ten sposób:

  1. Użyj klasy, która reprezentuje wybrane treści. Użyj klasy Parcelable, aby zapisać i przywrócić wybrany element listy. Użyj wtyczki kotlin-parcelize, aby wygenerować kod.
  2. Utwórz ThreePaneScaffoldNavigator z rememberListDetailPaneScaffoldNavigator.

Ten panel nawigacyjny służy do przechodzenia między listą, panelem szczegółów i dodatkowymi panelami. Dzięki zadeklarowaniu typu ogólnego nawigator śledzi też stan szablonu (czyli który MyItem jest wyświetlany). Ponieważ ten typ jest podzielny, stan może być zapisywany i przywracany przez nawigatora, aby automatycznie obsługiwać zmiany konfiguracji.

  1. Przekaż nawigatora do komponentu NavigableListDetailPaneScaffold.

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

  3. NavigableListDetailPaneScaffold umieść implementację panelu szczegółów.

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ść contentKey ma ten sam typ, który został określony w pierwotnym wywołaniu, dzięki czemu możesz uzyskać dostęp do dowolnych danych, które chcesz wyświetlić.

  1. Opcjonalnie zmień parametr defaultBackBehavior w pliku NavigableListDetailPaneScaffold. Domyślnie funkcja NavigableListDetailPaneScaffold używa wartości PopUntilScaffoldValueChange dla parametru defaultBackBehavior.

Jeśli Twoja aplikacja wymaga innego wzoru nawigacji wstecz, możesz zmienić to zachowanie, podając inną opcję BackNavigationBehavior.

Liczba opcji: BackNavigationBehavior

W tej sekcji używamy przykładu aplikacji pocztowej z listą e-maili w jednym panelu i widok szczegółowy w drugim.

To zachowanie dotyczy zmian w ogólnej strukturze układu. W przypadku konfiguracji z wieloma panelami zmiana treści e-maila w panelu szczegółowym nie zmienia podstawowej struktury układu. Dlatego przycisk Wstecz może zamykać aplikację lub bieżący graf nawigacji, ponieważ w bieżącym kontekście nie ma zmian układu, do których można wrócić. W układzie jednopanelowym naciśnięcie przycisku Wstecz spowoduje pominięcie zmian treści w widoku szczegółowym i powrót do widoku listy, ponieważ jest to wyraźna zmiana układu.

Zapoznaj się z tymi przykładami:

  • Wiele paneli: w panelu szczegółów wyświetlasz e-maila (element 1). Kliknięcie innego e-maila (element 2) powoduje zaktualizowanie panelu szczegółów, ale panele listy i szczegółów pozostają widoczne. Naciśnięcie przycisku Wstecz może spowodować zamknięcie aplikacji lub bieżącego procesu nawigacji.
  • Jedno okno: po wyświetleniu Elementu 1 i Elementu 2 naciśnięcie przycisku Wstecz spowoduje przejście bezpośrednio do panelu z listą e-maili.

Użyj tego, jeśli chcesz, aby użytkownicy widzieli różne przejścia między układami po każdym wykonaniu czynności wstecz.

Zmiana wartości nawigacji.
PopUntilContentChange

Dzięki temu wyświetlane treści są priorytetowe. Jeśli najpierw wyświetlisz Element 1, a potem Element 2, naciśnięcie przycisku Wstecz spowoduje powrót do Elementu 1, niezależnie od układu.

Zapoznaj się z tymi przykładami:

  • Wiele paneli: w panelu szczegółów wyświetlasz element 1, a następnie klikasz element 2 na liście. Panel szczegółów zostanie zaktualizowany. Naciśnięcie Wstecz spowoduje przywrócenie okna szczegółów do Elementu 1.
  • Jedno okno: następuje ta sama zmiana treści.

Użyj tego, gdy użytkownik chce wrócić do wcześniej wyświetlanych treści za pomocą przycisku Wstecz.

przejście między dwoma panelami szczegółowymi
PopUntilCurrentDestinationChange

Ta funkcja odsuwa karty w górę, aż bieżące miejsce docelowe nawigacji ulegnie zmianie. Dotyczy to zarówno układów pojedynczych, jak i wielopanelowych.

Zapoznaj się z tymi przykładami:

Niezależnie od tego, czy korzystasz z jednego czy z wielu paneli, naciśnięcie przycisku Wstecz zawsze spowoduje przeniesienie punktu skupienia z wybranego elementu nawigacji do poprzedniego miejsca docelowego. W naszej aplikacji pocztowej oznacza to, że wizualna wskazówka wybranego panelu zostanie przesunięta.

Używaj tego, gdy zachowanie wyraźnego wizualnego wskazania bieżącej nawigacji jest kluczowe dla wygody użytkowników.

przełączanie się między panelem szczegółów a panelem listy.
PopLatest

Ta opcja usuwa z backstacka tylko ostatni element. Użyj tej opcji, aby wrócić bez pomijania stanów pośrednich.

Po wykonaniu tych czynności kod powinien wyglądać mniej więcej tak:

val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
val scope = rememberCoroutineScope()

NavigableListDetailPaneScaffold(
    navigator = scaffoldNavigator,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    scope.launch {
                        scaffoldNavigator.navigateTo(
                            ListDetailPaneScaffoldRole.Detail,
                            item
                        )
                    }
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            scaffoldNavigator.currentDestination?.contentKey?.let {
                MyDetails(it)
            }
        }
    },
)