Grundlagen verstehen und implementieren

Die Navigation beschreibt, wie sich Nutzer in Ihrer App bewegen. Nutzer interagieren mit UI-Elementen, in der Regel durch Tippen oder Klicken, und die App reagiert darauf, indem sie neue Inhalte anzeigt. Wenn der Nutzer zum vorherigen Inhalt zurückkehren möchte, verwendet er die Touch-Geste „Zurück“ oder tippt auf die Schaltfläche „Zurück“.

Navigationsstatus modellieren

Eine praktische Möglichkeit, dieses Verhalten zu modellieren, ist ein Stapel von Inhalten. Wenn der Nutzer vorwärts zu neuen Inhalten navigiert, werden diese oben auf den Stapel gelegt. Wenn sie zurück zu diesem Inhalt gehen, wird er aus dem Stapel entfernt und der vorherige Inhalt wird angezeigt. In der Navigation wird dieser Stapel normalerweise als Backstack bezeichnet, da er die Inhalte darstellt, zu denen der Nutzer zurückkehren kann.

Eine Aktionsschaltfläche der Softwaretastatur (ein Häkchensymbol), die rot umrandet ist.
Abbildung 1: Diagramm, das zeigt, wie sich der Backstack bei Navigationsereignissen des Nutzers ändert.

Backstack erstellen

In Navigation 3 enthält der Backstack keinen Inhalt. Stattdessen enthält sie Verweise auf Inhalte, die als Schlüssel bezeichnet werden. Schlüssel können einen beliebigen Typ haben, sind aber in der Regel einfache, serialisierbare Datenklassen. Die Verwendung von Referenzen anstelle von Inhalten hat folgende Vorteile:

  • Die Navigation ist einfach, da Tasten auf den Backstack gelegt werden.
  • Solange die Schlüssel serialisierbar sind, kann der Backstack im persistenten Speicher gespeichert werden, sodass er Konfigurationsänderungen und das Beenden des Prozesses übersteht. Das ist wichtig, weil Nutzer erwarten, dass sie Ihre App verlassen, später wieder aufrufen und dort weitermachen können, wo sie aufgehört haben, wobei dieselben Inhalte angezeigt werden. Weitere Informationen finden Sie unter Backstack speichern.

Ein wichtiges Konzept in der Navigation 3-API ist, dass Sie den Backstack besitzen. Die Bibliothek:

  • Erwartet, dass Ihr Backstack ein Snapshot-State-basiertes List<T> ist, wobei T der Typ Ihres Backstack-keys ist. Sie können Any verwenden oder eigene, stärker typisierte Schlüssel bereitstellen. Wenn Sie die Begriffe „push“ oder „pop“ sehen, werden Elemente in der zugrunde liegenden Implementierung am Ende einer Liste hinzugefügt oder entfernt.
  • Beobachtet den Backstack und spiegelt seinen Status in der Benutzeroberfläche mithilfe eines NavDisplay wider.

Im folgenden Beispiel wird gezeigt, wie Sie Schlüssel und einen Backstack erstellen und den Backstack als Reaktion auf Navigationsereignisse von Nutzern ändern:

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

Schlüssel für Inhalte auflösen

In Navigation 3 wird Inhalt mit NavEntry modelliert. Das ist eine Klasse, die eine zusammensetzbare Funktion enthält. Sie stellt ein Ziel dar – einen einzelnen Inhalt, zu dem der Nutzer vorwärts und zurück navigieren kann.

Eine NavEntry kann auch Metadaten enthalten, also Informationen zum Inhalt. Diese Metadaten können von Containerobjekten wie NavDisplay gelesen werden, um zu entscheiden, wie die Inhalte des NavEntry angezeigt werden sollen. Mit Metadaten lassen sich beispielsweise die Standardanimationen für ein bestimmtes NavEntry überschreiben. NavEntry metadata ist eine Zuordnung von String-Schlüsseln zu Any-Werten, die eine vielseitige Datenspeicherung ermöglicht.

Wenn Sie eine key in eine NavEntry umwandeln möchten, erstellen Sie einen Entry Provider. Diese Funktion akzeptiert eine key und gibt eine NavEntry für diese key zurück. Er wird in der Regel als Lambdaparameter beim Erstellen eines NavDisplay definiert.

Es gibt zwei Möglichkeiten, einen Entry Provider zu erstellen: entweder direkt mit einer Lambda-Funktion oder mit der entryProvider-DSL.

Funktion für den Eintragsanbieter direkt erstellen

Normalerweise erstellen Sie eine Entry Provider-Funktion mit einer when-Anweisung mit einem Zweig für jeden Ihrer Schlüssel.

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") }
        }
    }
}

entryProvider-DSL verwenden

Mit der entryProvider-DSL können Sie Ihre Lambda-Funktion vereinfachen, da Sie nicht für jeden Ihrer Schlüsseltypen einen Test durchführen und für jeden einen NavEntry erstellen müssen. Verwenden Sie dazu die Builder-Funktion entryProvider. Außerdem ist ein Standard-Fallbackverhalten (Auslösen eines Fehlers) enthalten, wenn der Schlüssel nicht gefunden wird.

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

Beachten Sie Folgendes im Snippet:

  • Mit entry wird ein NavEntry mit dem angegebenen Typ und zusammensetzbaren Inhalt definiert.
  • entry akzeptiert einen metadata-Parameter zum Festlegen von NavEntry.metadata.

Backstack anzeigen

Der Backstack stellt den Navigationsstatus Ihrer App dar. Immer wenn sich der Backstack ändert, sollte die App-Benutzeroberfläche den neuen Backstack-Status widerspiegeln. In Navigation 3 beobachtet ein NavDisplay den Backstack und aktualisiert die Benutzeroberfläche entsprechend. Erstellen Sie sie mit den folgenden Parametern:

  • Ihr Backstack – dieser sollte vom Typ SnapshotStateList<T> sein, wobei T der Typ Ihrer Backstack-Schlüssel ist. Es ist ein beobachtbares List, sodass bei einer Änderung die Neuzusammensetzung von NavDisplay ausgelöst wird.
  • Ein entryProvider zum Konvertieren der Schlüssel in Ihrem Backstack in NavEntry-Objekte.
  • Optional können Sie dem Parameter onBack eine Lambda-Funktion übergeben. Diese Methode wird aufgerufen, wenn der Nutzer ein Zurück-Ereignis auslöst.

Das folgende Beispiel zeigt, wie ein NavDisplay erstellt wird.

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") }
            }
        }
    )
}

Standardmäßig wird im NavDisplay das oberste NavEntry im Backstack in einem Layout mit einem Bereich angezeigt. Die folgende Aufnahme zeigt die Ausführung dieser App:

Standardverhalten von „NavDisplay“ mit zwei Zielen.
Abbildung 2. NavDisplay-Standardverhalten mit zwei Zielen.

Zusammenfassung

Das folgende Diagramm zeigt, wie Daten zwischen den verschiedenen Objekten in Navigation 3 fließen:

Eine Visualisierung des Datenflusses zwischen den verschiedenen Objekten in Navigation 3.
Abbildung 3: Diagramm, das zeigt, wie Daten durch verschiedene Objekte in Navigation 3 fließen.
  1. Navigationsereignisse lösen Änderungen aus: Schlüssel werden als Reaktion auf Nutzerinteraktionen dem Backstack hinzugefügt oder daraus entfernt.

  2. Änderung des Backstack-Status löst das Abrufen von Inhalten aus: Die NavDisplay-Funktion (eine zusammensetzbare Funktion, die einen Backstack rendert) beobachtet den Backstack. In der Standardkonfiguration wird der oberste Backstack-Eintrag in einem Layout mit einem einzelnen Bereich angezeigt. Wenn sich der oberste Schlüssel im Backstack ändert, verwendet NavDisplay diesen Schlüssel, um die entsprechenden Inhalte vom Eintragsanbieter anzufordern.

  3. Eintragsanbieter stellt Inhalte bereit: Der Eintragsanbieter ist eine Funktion, die einen Schlüssel in ein NavEntry auflöst. Nachdem der Eintraganbieter einen Schlüssel von NavDisplay erhalten hat, stellt er die zugehörige NavEntry bereit, die sowohl den Schlüssel als auch die Inhalte enthält.

  4. Inhalte werden angezeigt: Das NavDisplay empfängt das NavEntry und zeigt den Inhalt an.