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, wykonuje gest 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 z działaniami użytkownika związanymi z przemieszczaniem się po aplikacji.

Tworzenie ścieżki wstecznej

W wersji 3 nawigacji 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ć, naciskając klawisze.
  • Dopóki klucze można zserializować, można zapisać stos w pamięci trwałej, 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ń.

Kluczową 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> z archiwizowanym stanem migawki, 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 apek i odzwierciedla jego stan w interfejsie za pomocą NavDisplay.

Ten przykład pokazuje, jak utworzyć klucze i stół z elementami poprzednich poziomów oraz zmodyfikować ten stół w odpowiedzi na zdarzenia związane z przejściem użytkownika do innej strony:

// 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()
}

Przypisywanie kluczy do treści

Treści są modelowane w Nawigacji 3 za pomocą elementu NavEntry, który jest klasą zawierającą funkcję składającą się z elementów. Reprezentuje miejsce docelowe – pojedynczy element treści, do którego użytkownik może przejść i z niego 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 mapowanie kluczy String na wartości Any, które zapewnia wszechstronne przechowywanie danych.

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

Dostęp do dostawcy wpisów można uzyskać na 2 sposoby: bezpośrednio tworząc funkcję lambda lub za pomocą języka opisu entryProvider.

Bezpośrednie tworzenie funkcji dostawcy danych wejściowych

Funkcję dostawcy danych wejściowych zwykle 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ą łączenia treści.
  • entry przyjmuje parametr metadata, aby ustawić NavEntry.metadata

Wyświetlanie stosu poprzednich elementów

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 usługa NavDisplay monitoruje stos i odpowiednio aktualizuje interfejs. Utwórz go z tymi parametrami:

  • Powrót do stosu – powinien mieć typ SnapshotStateList<T>, gdzie T to typ kluczy z powrotu do stosu. 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 funkcję lambda w parametrze onBack. 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. Domyślne działanie typu NavDisplay 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 z poprzednich elementów) obserwuje stos z poprzednich elementów. W domyślnej konfiguracji wyświetla ona najwyższy element wstecznej ścieżki 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 przekazuje 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ść.