Poznawanie i wdrażanie podstaw

Nawigacja określa sposób poruszania się użytkowników po aplikacji. Użytkownicy wchodzą w interakcje z elementami interfejsu, zwykle przez ich klikanie lub dotykanie, a aplikacja reaguje, wyświetlając nowe treści. Jeśli użytkownik chce wrócić do poprzednich treści, używa gestu cofania lub klika przycisk Wstecz.

Modelowanie stanu nawigacji

Wygodne modelowanie tego zachowania polega na zastosowaniu zbioru treści. Gdy użytkownik przechodzi do nowych treści, są one przesuwane na wierzch stosu. Gdy powrócą do tej zawartości, zostanie ona usunięta ze stosu i wyświetli się poprzednia zawartość. W terminologii nawigacji ten zestaw nazywany jest zwykle zestawem poprzednich stron, ponieważ zawiera treści, do których użytkownik może wrócić.

Czerwony okrąg z ikoną przycisku akcji klawiatury ekranowej (ikona potwierdzenia).
Rysunek 1. Diagram pokazujący, jak zmienia się stos wsteczny w związku ze zdarzeniami nawigacji użytkownika.

Tworzenie ścieżki wstecznej

W wersji Nawigacja 3 stos wsteczny nie zawiera treści. Zamiast tego zawiera odwołania do treści, czyli klucze. Klucze mogą być dowolnego typu, ale zazwyczaj są to proste, serializowane klasy danych. Korzystanie z odwołań zamiast treści ma te zalety:

  • Łatwo się po nim poruszać, przesuwając elementy na wyższy poziom.
  • Dopóki klucze można zserializować, można zapisać stos w trwałym miejscu przechowywania, co pozwoli mu przetrwać zmiany konfiguracji i zakończenie procesu. Jest to ważne, ponieważ użytkownicy oczekują, że mogą opuścić Twoją aplikację, wrócić do niej później i wziąć ją od miejsca, w którym ją opuścili, z tymi samymi treściami. Więcej informacji znajdziesz w artykule Zachowywanie historii wywołań.

Ważną koncepcją w interfejsie Navigation 3 API jest to, że masz kontrolę nad stosem wstecznym. Biblioteka:

  • Oczekuje, że zespół z poziomu poprzedniego będzie mieć stan List<T>, gdzie T to typ zespołu z poziomu poprzedniego keys. Możesz użyć Any lub podać własne klucze o bardziej ścisłym typie. Gdy widzisz terminy „push” lub „pop”, oznacza to, że implementacja polega na dodawaniu lub usuwaniu elementów z końca listy.
  • Obserwuje stos i odzwierciedla jego stan w interfejsie użytkownika za pomocą elementu NavDisplay.

Ten przykład pokazuje, jak utworzyć klucze i stół z elementami do cofnięcia oraz jak zmodyfikować ten stół w odpowiedzi na zdarzenia związane z przeglądaniem treści przez użytkownika:

// Define keys that will identify content
data object ProductList
data class ProductDetail(val id: String)

@Composable
fun MyApp() {

    // Create a back stack, specifying the key the app should start with
    val backStack = remember { mutableStateListOf<Any>(ProductList) }

    // Supply your back stack to a NavDisplay so it can reflect changes in the UI
    // ...more on this below...

    // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state
    backStack.add(ProductDetail(id = "ABC"))

    // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state
    backStack.removeLastOrNull()
}

Rozwiązywanie kluczy w treści

Treści są modelowane w Nawigacji 3 za pomocą klasy NavEntry, która zawiera funkcję składającą się z elementów. Reprezentuje miejsce docelowe, czyli pojedynczy element treści, do którego użytkownik może przejść i z którego może wrócić.

NavEntry może też zawierać metadane – informacje o treści. Te metadane mogą być odczytywane przez obiekty kontenera, takie jak NavDisplay, aby pomóc im zdecydować, jak wyświetlić zawartość NavEntry. Metadanych można na przykład używać do zastępowania domyślnych animacji w przypadku konkretnego NavEntry. NavEntry metadata to mapa kluczy String na wartości Any, która zapewnia wszechstronne przechowywanie danych.

Aby przekształcić key w NavEntry, utwórz entryProvider. To funkcja, która przyjmuje key i zwraca NavEntry dla tego key. Jest on zwykle definiowany jako parametr lambda podczas tworzenia NavDisplay.

Istnieją 2 sposoby tworzenia entryProvider: bezpośrednio za pomocą funkcji lambda lub za pomocą języka entryProvider DSL.

bezpośrednie tworzenie funkcji entryProvider,

Funkcję entryProvider zazwyczaj tworzy się za pomocą instrukcji when, z odgałęziami dla każdego klucza.

entryProvider = { key ->
    when (key) {
        is ProductList -> NavEntry(key) { Text("Product List") }
        is ProductDetail -> NavEntry(
            key,
            metadata = mapOf("extraDataKey" to "extraDataValue")
        ) { Text("Product ${key.id} ") }

        else -> {
            NavEntry(Unit) { Text(text = "Invalid Key: $it") }
        }
    }
}

Użyj DSL entryProvider

Dzięki językowi entryProvider DSL możesz uprościć funkcję lambda, ponieważ nie musisz testować każdego typu klucza i tworzyć dla każdego z nich NavEntry. W tym celu użyj funkcji konstruktora entryProvider. Obejmuje ono też domyślne zachowanie zastępcze (zwracanie błędu), jeśli klucz nie zostanie znaleziony.

entryProvider = entryProvider {
    entry<ProductList> { Text("Product List") }
    entry<ProductDetail>(
        metadata = mapOf("extraDataKey" to "extraDataValue")
    ) { key -> Text("Product ${key.id} ") }
}

Zwróć uwagę na te informacje w fragmentach kodu:

  • entry służy do definiowania NavEntry o danym typie i z możliwością składania treści.
  • entry przyjmuje parametr metadata, aby ustawić NavEntry.metadata

Wyświetlanie stosu elementów do tyłu

Stos wstecz reprezentuje stan nawigacji w aplikacji. Gdy zmienia się kolejność elementów w grupie elementów wstecz, interfejs aplikacji powinien odzwierciedlać nowy stan tej grupy. W ramach Nawigacji 3 komponentNavDisplay obserwuje stos i odpowiednio aktualizuje interfejs. Utwórz go z tymi parametrami:

  • Powrót do sterowania – powinien mieć typ SnapshotStateList<T>, gdzie T to typ kluczy sterowania. Jest to obserwowalna wartość List, która po zmianie powoduje przekształcenie wartości NavDisplay.
  • entryProvider, aby zamienić klucze w grupie poprzednich elementów na NavEntry.
  • Opcjonalnie podaj w parametrze onBack funkcję lambda. Jest wywoływany, gdy użytkownik wywoła zdarzenie wstecz.

Z poniższego przykładu dowiesz się, jak utworzyć NavDisplay.

data object Home
data class Product(val id: String)

@Composable
fun NavExample() {

    val backStack = remember { mutableStateListOf<Any>(Home) }

    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeLastOrNull() },
        entryProvider = { key ->
            when (key) {
                is Home -> NavEntry(key) {
                    ContentGreen("Welcome to Nav3") {
                        Button(onClick = {
                            backStack.add(Product("123"))
                        }) {
                            Text("Click to navigate")
                        }
                    }
                }

                is Product -> NavEntry(key) {
                    ContentBlue("Product ${key.id} ")
                }

                else -> NavEntry(Unit) { Text("Unknown route") }
            }
        }
    )
}

Domyślnie NavDisplay wyświetla najwyższy NavEntry w grupie warstw w układzie z jednym panelem. Na poniższym nagraniu widać uruchomioną aplikację:

Domyślne zachowanie `NavDisplay` z 2 miejscami docelowymi.
Rysunek 2. NavDisplay zachowanie domyślne z 2 miejscami docelowymi.

Podsumowanie

Ten diagram pokazuje, jak dane przepływają między różnymi obiektami w ramach funkcji Nawigacja 3:

Wizualizacja przepływu danych między różnymi obiektami w Nawigacji 3.
Rysunek 3. Diagram pokazujący, jak dane przepływają przez różne obiekty w Nawigacji 3.
  1. Zdarzenia dotyczące nawigacji inicjują zmiany. Klucze są dodawane do stosu lub usuwane z niego w odpowiedzi na interakcje użytkownika.

  2. Zmiana stanu stosu wywołuje pobieranie treści. NavDisplay(element składany, który renderuje stos wsteczny) obserwuje stos wsteczny. W domyślnej konfiguracji wyświetla ona najwyższy element wstecznej ścieżki wywołań w układzie z jednym panelem. Gdy zmienia się górny klucz w zbiorze, NavDisplay używa tego klucza do żądania odpowiedniej treści od dostawcy danych.

  3. Dostawca danych dostarcza treści. Dostawca danych wejściowych to funkcja, która rozwiązuje klucz na NavEntry. Po otrzymaniu klucza od NavDisplay dostawca danych udostępnia powiązany NavEntry, który zawiera zarówno klucz, jak i treści.

  4. Treści są wyświetlane. NavDisplay otrzymuje NavEntry i wyświetla zawartość.