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 darauf, und die App reagiert, indem sie neue Inhalte anzeigt. Wenn der Nutzer zu den vorherigen Inhalten 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 sich der Nutzer vorwärts zu neuen Inhalten bewegt, werden diese auf den Stapel gelegt. Wenn der Nutzer zurück zu diesem Inhalt wechselt, wird er aus dem Stapel entfernt und der vorherige Inhalt wird angezeigt. In der Navigation wird dieser Stack in der Regel als Backstack bezeichnet, da er die Inhalte darstellt, zu denen der Nutzer zurückkehren kann.

Eine Aktionsschaltfläche der Softwaretastatur (ein Häkchensymbol) in rotem Kreis.
Abbildung 1: Diagramm, das zeigt, wie sich der Rückstapel bei Navigationsereignissen des Nutzers ändert.

Backstack erstellen

In Navigation 3 enthält der Rückstapel keine Inhalte. Stattdessen enthält sie Referenzen auf Inhalte, die als Schlüssel bezeichnet werden. Schlüssel können beliebigen Typs sein, sind aber in der Regel einfache, serialisierbare Datenklassen. Die Verwendung von Referenzen anstelle von Inhalten bietet folgende Vorteile:

  • Die Navigation ist einfach, da Tasten auf den Rückstapel gedrückt werden.
  • Solange die Schlüssel serialisierbar sind, kann der Backstack im nichtflüchtigen Speicher gespeichert werden, sodass er Konfigurationsänderungen und das Ende des Prozesses überdauert. Das ist wichtig, weil Nutzer davon ausgehen, dass sie Ihre App verlassen, später wieder zurückkehren 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 für den Backstack verantwortlich sind. Die Bibliothek:

  • Es wird davon ausgegangen, dass Ihr Backstack ein List<T> mit Snapshot-Status ist, wobei T der Typ Ihres Backstacks keys ist. Sie können Any verwenden oder eigene, stärker typisierte Schlüssel angeben. Wenn Sie die Begriffe „Push“ oder „Pop“ sehen, werden damit Elemente am Ende einer Liste hinzugefügt oder entfernt.
  • Beobachtet den Backstack und spiegelt seinen Status in der Benutzeroberfläche mithilfe einer NavDisplay wider.

Das folgende Beispiel zeigt, wie Sie Schlüssel und einen Backstack erstellen und den Backstack als Reaktion auf Navigationsereignisse des Nutzers ä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 zu Inhalten auflösen

In Navigation 3 werden Inhalte mit NavEntry modelliert, einer Klasse mit einer kombinierbaren Funktion. Sie stellt ein Ziel dar, also einen einzelnen Inhalt, zu dem Nutzer vor- und zurück springen können.

Ein 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 können Sie beispielsweise die Standardanimationen für eine bestimmte NavEntry überschreiben. „NavEntry“metadata ist eine Zuordnung von String-Schlüsseln zu Any-Werten, die einen vielseitigen Datenspeicher bietet.

Wenn Sie einen key in einen NavEntry konvertieren möchten, erstellen Sie einen entryProvider. Dies ist eine Funktion, die eine key akzeptiert und für diese key eine NavEntry zurückgibt. Sie wird beim Erstellen einer NavDisplay in der Regel als Lambda-Parameter definiert.

Es gibt zwei Möglichkeiten, eine entryProvider zu erstellen: Sie können entweder direkt eine Lambda-Funktion erstellen oder die entryProvider-DSL verwenden.

entryProvider-Funktion direkt erstellen

Normalerweise erstellen Sie eine entryProvider-Funktion mit einer when-Anweisung mit einem Verzweigungspunkt für jeden 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 jeden Schlüsseltyp testen und für jeden eine NavEntry erstellen müssen. Verwenden Sie dazu die Builder-Funktion entryProvider. Außerdem wird das standardmäßige Fallback-Verhalten (Auslösen eines Fehlers) angegeben, falls 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 Inhalten definiert.
  • entry akzeptiert einen metadata-Parameter, um NavEntry.metadata festzulegen.

Rückstapel anzeigen

Der Backstack stellt den Navigationsstatus Ihrer App dar. 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:

  • Der Backstack: Dieser sollte vom Typ SnapshotStateList<T> sein, wobei T der Typ Ihrer Backstack-Schlüssel ist. Es ist eine beobachtbare List, die bei Änderungen eine Neuzusammensetzung von NavDisplay auslöst.
  • Ein entryProvider, um die Schlüssel im Backstack in NavEntrys umzuwandeln.
  • Optional können Sie dem Parameter onBack ein Lambda-Objekt übergeben. 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 zeigt die NavDisplay die oberste NavEntry im Rückstapel in einem einzeiligen Layout an. In der folgenden Aufzeichnung ist diese App zu sehen:

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 den Datenfluss durch verschiedene Objekte in Navigation 3 zeigt
  1. Navigationsereignisse initiieren Änderungen. Schlüssel werden als Reaktion auf Nutzerinteraktionen dem Backstack hinzugefügt oder daraus entfernt.

  2. Eine Änderung des Status des Backstacks löst das Abrufen von Inhalten aus. NavDisplay (ein Composeable, das einen Backstack rendert) beobachtet den Backstack. In der Standardkonfiguration wird der oberste Backstack-Eintrag in einem einzelnen Ansichtsbereich angezeigt. Wenn sich der oberste Schlüssel im Backstack ändert, verwendet NavDisplay diesen Schlüssel, um die entsprechenden Inhalte vom Eingabeanbieter anzufordern.

  3. Der Datenanbieter stellt die Inhalte bereit. Der Eintragsanbieter ist eine Funktion, die einen Schlüssel in eine NavEntry auflöst. Wenn der Eintragsanbieter einen Schlüssel von der NavDisplay erhält, stellt er die zugehörige NavEntry bereit, die sowohl den Schlüssel als auch den Inhalt enthält.

  4. Inhalte werden angezeigt. Die NavDisplay empfängt die NavEntry und zeigt den Inhalt an.