Poznawanie i wdrażanie podstaw

Nawigacja opisuje sposób poruszania się użytkowników po aplikacji. Użytkownicy wchodzą w interakcje z elementami interfejsu, zwykle klikając je lub dotykając, a aplikacja odpowiada, 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

Wygodnym sposobem modelowania tego zachowania jest stos treści. Gdy użytkownik przechodzi dalej do nowych treści, są one umieszczane na górze stosu. Gdy użytkownik wróci z tej treści, zostanie ona usunięta ze stosu i wyświetli się poprzednia treść. W terminologii nawigacyjnej ten stos jest zwykle nazywany stosem wstecznym, ponieważ reprezentuje treści, do których użytkownik może wrócić.

Przycisk działania klawiatury ekranowej (ikona potwierdzenia) zakreślony na czerwono.
Rysunek 1. Diagram pokazujący, jak zmienia się stos wsteczny w zależności od zdarzeń nawigacji użytkownika.

Tworzenie listy wstecznej

W Navigation 3 lista wsteczna nie zawiera treści. Zamiast tego zawiera odniesienia do treści, zwane kluczami. Klucze mogą być dowolnego typu, ale zwykle są to proste, serializowane klasy danych. Używanie odwołań zamiast treści ma następujące zalety:

  • Nawigacja jest prosta – wystarczy nacisnąć klawisze na tylnej części urządzenia.
  • Dopóki klucze są serializowane, można zapisać stos wsteczny w pamięci trwałej, dzięki czemu przetrwa on zmiany konfiguracji i zakończenie procesu. Jest to ważne, ponieważ użytkownicy oczekują, że po opuszczeniu aplikacji i późniejszym powrocie do niej będą mogli kontynuować korzystanie z tych samych treści. Więcej informacji znajdziesz w artykule Zapisywanie listy poprzednich ekranów.

Kluczową koncepcją interfejsu Navigation 3 API jest to, że stos wsteczny należy do Ciebie. Biblioteka:

  • Oczekuje, że stos wsteczny będzie kopią stanu List<T>, gdzie T to typ stosu wstecznego keys. Możesz użyć Any lub podać własne, bardziej szczegółowe klucze. Gdy zobaczysz terminy „push” lub „pop”, oznacza to, że w tle dodawane lub usuwane są elementy z końca listy.
  • Obserwuje stos wsteczny i odzwierciedla jego stan w interfejsie za pomocą NavDisplay.

W tym przykładzie pokazujemy, jak tworzyć klucze i stos wsteczny oraz modyfikować stos wsteczny w odpowiedzi na zdarzenia nawigacji 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 do treści

Treści w Navigation 3 są modelowane za pomocą NavEntry, czyli klasy zawierającej funkcję kompozycyjną. Reprezentuje miejsce docelowe – 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, czyli informacje o treści. Te metadane mogą być odczytywane przez obiekty kontenera, takie jak NavDisplay, aby pomóc im zdecydować, jak wyświetlać zawartość NavEntry. Metadane mogą na przykład służyć do zastępowania domyślnych animacji w przypadku konkretnego NavEntry. NavEntry metadata to mapa String kluczy do Any wartości, która zapewnia wszechstronne przechowywanie danych.

Aby przekonwertować key na NavEntry, utwórz dostawcę wpisów. Jest to funkcja, która przyjmuje key i zwraca NavEntry dla tego key. Zwykle jest on definiowany jako parametr lambda podczas tworzenia NavDisplay.

Dostawcę wpisów można utworzyć na 2 sposoby: bezpośrednio tworząc funkcję lambda lub za pomocą języka DSL entryProvider.

Bezpośrednie tworzenie funkcji dostawcy wpisów

Funkcję Entry Provider tworzy się zwykle za pomocą instrukcji when, z gałęzią 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żywanie języka DSL entryProvider

entryProvider DSL może uprościć funkcję lambda, ponieważ nie musisz testować każdego typu klucza ani tworzyć NavEntry dla każdego z nich. Użyj w tym celu funkcji entryProvider. Obejmuje też domyślne zachowanie rezerwowe (zgłaszanie 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:

  • entry służy do definiowania NavEntry o danym typie i zawartości, którą można łączyć.
  • entry akceptuje parametr metadata, aby ustawić NavEntry.metadata

Wyświetlanie stosu wstecznego

Stos wsteczny reprezentuje stan nawigacji w aplikacji. Za każdym razem, gdy zmienia się stos wsteczny, interfejs aplikacji powinien odzwierciedlać nowy stan stosu wstecznego. W Navigation 3 komponent NavDisplay obserwuje stos wsteczny i odpowiednio aktualizuje interfejs. Utwórz go, podając te parametry:

  • Lista wsteczna – powinna być typu SnapshotStateList<T>, gdzie T to typ kluczy listy wstecznej. Jest to obserwowalny List, więc gdy się zmieni, spowoduje ponowne skomponowanie NavDisplay.
  • entryProvider – przekształca klucze w stosie wstecznym w NavEntryobiekty.
  • Opcjonalnie możesz podać funkcję lambda w parametrze onBack. Ta funkcja jest wywoływana, gdy użytkownik wywoła zdarzenie powrotu.

Poniższy przykład pokazuje, 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 element NavEntry na liście wstecznej w układzie z 1 panelem. Na tym nagraniu widać działanie aplikacji:

Domyślne działanie komponentu `NavDisplay` z 2 miejscami docelowymi.
Rysunek 2. NavDisplay domyślne działanie z 2 miejscami docelowymi

Podsumowanie

Ten diagram pokazuje przepływ danych między różnymi obiektami w Nawigacji 3:

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

  2. Zmiana stanu listy wstecznej powoduje pobranie treści. Funkcja NavDisplay (kompozycja, która renderuje stos wsteczny) obserwuje stos wsteczny. W konfiguracji domyślnej wyświetla ona najwyższy wpis z listy wstecznej w układzie z jednym panelem. Gdy zmieni się klucz u góry stosu wstecznego, NavDisplay używa tego klucza, aby poprosić dostawcę wpisu o odpowiednie treści.

  3. Dostawca wpisu dostarcza treści Dostawca wpisu to funkcja, która przekształca klucz w wartość NavEntry. Po otrzymaniu klucza od NavDisplay dostawca wpisu udostępnia powiązany NavEntry, który zawiera zarówno klucz, jak i treść.

  4. Treści są wyświetlane. Urządzenie NavDisplay odbiera NavEntry i wyświetla treści.