Navigationsdiagramm entwerfen

Die Navigationskomponente verwendet einen Navigationsgraphen, um die Navigation Ihrer App zu verwalten. Der Navigationsgraph ist eine Datenstruktur, die alle Ziele in Ihrer App und die Verbindungen zwischen ihnen enthält.

Zieltypen

Es gibt drei allgemeine Zieltypen: gehostete, Dialog- und Aktivitätsziele. In der folgenden Tabelle werden diese drei Zieltypen und ihre Zwecke beschrieben.

Eingeben

Beschreibung

Anwendungsfälle

Gehostet

Füllt den gesamten Navigationshost aus. Das heißt, die Größe eines gehosteten Ziels entspricht der Größe des Navigationshosts und vorherige Ziele sind nicht sichtbar.

Haupt- und Detailbildschirm

Dialogfeld

Zeigt UI-Overlay-Komponenten an. Diese Benutzeroberfläche ist nicht an den Standort oder die Größe des Navigationshosts gebunden. Bisherige Ziele werden unter dem Ziel angezeigt.

Benachrichtigungen, Auswahlen, Formulare.

Aktivität

Stellt eindeutige Bildschirme oder Funktionen in der App dar.

Als Ausstiegspunkt für den Navigationsgraphen dienen, über den eine neue Android-Aktivität gestartet wird, die separat von der Navigationskomponente verwaltet wird.

Bei der modernen Android-Entwicklung besteht eine App aus einer einzelnen Aktivität. Aktivitätsziele eignen sich daher am besten für Interaktionen mit Aktivitäten von Drittanbietern oder als Teil des Migrationsprozesses.

Dieses Dokument enthält Beispiele für gehostete Ziele, die am häufigsten und grundlegendsten sind. Informationen zu den anderen Zielen finden Sie in den folgenden Leitfäden:

Frameworks

Obwohl in jedem Fall derselbe allgemeine Workflow gilt, hängt es vom verwendeten UI-Framework ab, wie genau Sie einen Navigationshost und ein Navigationsdiagramm erstellen.

  • Compose (Komponieren): Verwenden Sie das NavHost-Element. Fügen Sie mit der Kotlin-DSL ein NavGraph hinzu. Es gibt zwei Möglichkeiten, den Graphen zu erstellen:
    • Im NavHost:Erstellen Sie den Navigationsgraphen direkt beim Hinzufügen der NavHost.
    • Programmatisch:Verwenden Sie die Methode NavController.createGraph(), um eine NavGraph zu erstellen und direkt an die NavHost zu übergeben.
  • Fragmente:Wenn Sie Fragmente mit dem UI-Framework von Google-Diensten verwenden, verwenden Sie NavHostFragment als Host. Es gibt mehrere Möglichkeiten, einen Navigationsgraphen zu erstellen:
    • Programmatisch:Mit der Kotlin DSL eine NavGraph erstellen und direkt auf die NavHostFragment anwenden.
      • Die createGraph()-Funktion, die in der Kotlin-DSL sowohl für Fragmente als auch für Compose verwendet wird, ist dieselbe.
    • XML:Sie können den Navigationshost und das Diagramm direkt in XML schreiben.
    • Android Studio-Editor:Mit dem GUI-Editor in Android Studio können Sie Ihre Grafik als XML-Ressourcendatei erstellen und anpassen.

Schreiben

Verwenden Sie in Compose ein serialisierbares Objekt oder eine serialisierbare Klasse, um eine Route zu definieren. Eine Route beschreibt, wie Sie zu einem Ziel gelangen, und enthält alle Informationen, die für das Ziel erforderlich sind.

Verwenden Sie die Anmerkung @Serializable, um automatisch die erforderlichen Serializations- und Deserializationsmethoden für Ihre Routentypen zu erstellen. Diese Anmerkung wird vom Kotlin-Serialisierungs-Plug-in bereitgestellt. Folgen Sie dieser Anleitung, um das Plug-in hinzuzufügen.

Nachdem Sie Ihre Routen definiert haben, erstellen Sie mit dem NavHost-Element den Navigationsgraphen. Betrachten Sie das folgende Beispiel:

@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
    // Add more destinations similarly.
}
  1. Ein serialisierbares Objekt steht für jede der beiden Routen, Profile und FriendsList.
  2. Der Aufruf an das NavHost-Kompositelement übergibt einen NavController und eine Route für das Startziel.
  3. Das an NavHost übergebene Lambda ruft letztendlich NavController.createGraph() auf und gibt einen NavGraph zurück.
  4. Jede Route wird als Typargument an NavGraphBuilder.composable<T>() übergeben, wodurch das Ziel der resultierenden NavGraph hinzugefügt wird.
  5. Das an composable übergebene Lambda wird in NavHost für dieses Ziel angezeigt.

Lambda

Um das Lambda besser zu verstehen, mit dem die NavGraph erstellt wird, können Sie sich vorstellen, dass Sie denselben Graphen wie im vorherigen Snippet erstellen, indem Sie die NavGraph separat mit NavController.createGraph() erstellen und direkt an die NavHost übergeben:

val navGraph by remember(navController) {
  navController.createGraph(startDestination = Profile)) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
  }
}
NavHost(navController, navGraph)

Karten-/Ticketargumente

Wenn Sie Daten an ein Ziel übergeben müssen, definieren Sie die Route mit einer Klasse mit Parametern. Die Route Profile ist beispielsweise eine Datenklasse mit einem name-Parameter.

@Serializable
data class Profile(val name: String)

Wenn Sie diesem Ziel Argumente übergeben müssen, erstellen Sie eine Instanz Ihrer Routenklasse und übergeben die Argumente an den Klassenkonstruktor.

Erstellen Sie für optionale Argumente Felder mit Nullwerten und einem Standardwert.

@Serializable
data class Profile(val nickname: String? = null)

Routen-Instanz abrufen

Sie können die Routen-Instanz mit NavBackStackEntry.toRoute() oder SavedStateHandle.toRoute() abrufen. Wenn Sie ein Ziel mit composable() erstellen, ist NavBackStackEntry als Parameter verfügbar.

@Serializable
data class Profile(val name: String)

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(name = profile.name) }
}

Beachten Sie in diesem Snippet Folgendes:

  • Die Route Profile gibt den Startpunkt im Navigationsgraphen an, wobei "John Smith" das Argument für name ist.
  • Das Ziel selbst ist der composable<Profile>{}-Block.
  • Das ProfileScreen-Komposit nimmt den Wert von profile.name für sein eigenes name-Argument an.
  • Daher wird der Wert "John Smith" an ProfileScreen übergeben.

Minimalbeispiel

Vollständiges Beispiel für die Kombination von NavController und NavHost:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
    profile: Profile
    onNavigateToFriendsList: () -> Unit,
  ) {
  Text("Profile for ${profile.name}")
  Button(onClick = { onNavigateToFriendsList() }) {
    Text("Go to Friends List")
  }
}

// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
  Text("Friends List")
  Button(onClick = { onNavigateToProfile() }) {
    Text("Go to Profile")
  }
}

// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
  val navController = rememberNavController()
  NavHost(navController, startDestination = Profile(name = "John Smith")) {
    composable<Profile> { backStackEntry ->
        val profile: Profile = backStackEntry.toRoute()
        ProfileScreen(
            profile = profile,
            onNavigateToFriendsList = {
                navController.navigate(route = FriendsList)
            }
        )
    }
    composable<FriendsList> {
      FriendsListScreen(
        onNavigateToProfile = {
          navController.navigate(
            route = Profile(name = "Aisha Devi")
          )
        }
      )
    }
  }
}

Wie das Snippet zeigt, wird die NavController nicht an Ihre Composeables übergeben, sondern ein Ereignis wird der NavHost zur Verfügung gestellt. Das heißt, Ihre Composeables sollten einen Parameter vom Typ () -> Unit haben, für den NavHost ein Lambda übergibt, das NavController.navigate() aufruft.

Fragmente

Wie in den vorherigen Abschnitten beschrieben, haben Sie bei der Verwendung von Fragmenten die Möglichkeit, einen Navigationsgraphen programmatisch mit der Kotlin-DSL, XML oder dem Android Studio-Editor zu erstellen.

In den folgenden Abschnitten werden diese verschiedenen Ansätze beschrieben.

Programmatisch

Die Kotlin-DSL bietet eine programmatische Möglichkeit, einen Navigationsgraphen mit Fragmenten zu erstellen. Das ist in vielerlei Hinsicht übersichtlicher und moderner als die Verwendung einer XML-Ressourcendatei.

Betrachten Sie das folgende Beispiel, in dem ein Navigationsgraph mit zwei Bildschirmen implementiert ist.

Zuerst müssen Sie die NavHostFragment erstellen. Sie darf kein app:navGraph-Element enthalten:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

Übergeben Sie als Nächstes die id der NavHostFragment an NavController.findNavController. Dadurch wird der NavController mit der NavHostFragment verknüpft.

Anschließend wird durch den Aufruf von NavController.createGraph() die Grafik mit der NavController und damit auch mit der NavHostFragment verknüpft:

@Serializable
data class Profile(val name: String)

@Serializable
object FriendsList

// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)

// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
    startDestination = Profile(name = "John Smith")
) {
    // Associate each destination with one of the route constants.
    fragment<ProfileFragment, Profile> {
        label = "Profile"
    }

    fragment<FriendsListFragment, FriendsList>() {
        label = "Friends List"
    }

    // Add other fragment destinations similarly.
}

Die Verwendung der DSL auf diese Weise ähnelt dem Workflow, der im vorherigen Abschnitt zu Compose beschrieben wurde. Sowohl dort als auch hier wird beispielsweise die NavGraph durch die Funktion NavController.createGraph() generiert. Ebenso wird mit NavGraphBuilder.composable() dem Diagramm ein zusammensetzbares Ziel hinzugefügt, während hier mit NavGraphBuilder.fragment() ein Fragmentziel hinzugefügt wird.

Weitere Informationen zur Verwendung der Kotlin-DSL finden Sie unter Graphen mit der NavGraphBuilder-DSL erstellen.

XML

Sie können die XML-Datei auch selbst schreiben. Das folgende Beispiel entspricht dem Beispiel mit zwei Bildschirmen aus dem vorherigen Abschnitt.

Erstellen Sie zuerst eine NavHostFragment. Dieser dient als Navigationshost, der das eigentliche Navigationsdiagramm enthält.

Eine minimale Implementierung eines NavHostFragment:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/nav_graph" />

</FrameLayout>

NavHostFragment enthält das Attribut app:navGraph. Verwenden Sie dieses Attribut, um Ihren Navigationsgraphen mit dem Navigationshost zu verbinden. Im Folgenden finden Sie ein Beispiel für die Implementierung des Diagramms:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/profile">

    <fragment
        android:id="@+id/profile"
        android:name="com.example.ProfileFragment"
        android:label="Profile">

        <!-- Action to navigate from Profile to Friends List. -->
        <action
            android:id="@+id/action_profile_to_friendslist"
            app:destination="@id/friendslist" />
    </fragment>

    <fragment
        android:id="@+id/friendslist"
        android:name="com.example.FriendsListFragment"
        android:label="Friends List" />

    <!-- Add other fragment destinations similarly. -->
</navigation>

Mit Aktionen definieren Sie die Verbindungen zwischen verschiedenen Zielen. In diesem Beispiel enthält das profile-Fragment eine Aktion, die zu friendslist führt. Weitere Informationen finden Sie unter Navigationsaktionen und ‑fragmente verwenden.

Editor

Sie können den Navigationsgraphen Ihrer App mit dem Navigationseditor in Android Studio verwalten. Dies ist im Wesentlichen eine Benutzeroberfläche, mit der Sie Ihre NavigationFragment-XML-Datei erstellen und bearbeiten können, wie im vorherigen Abschnitt gezeigt.

Weitere Informationen finden Sie unter Navigationseditor.

Verschachtelte Grafiken

Sie können auch verschachtelte Diagramme verwenden. Dazu wird ein Graph als Navigationsziel verwendet. Weitere Informationen finden Sie unter Verschachtelte Diagramme.

Weitere Informationen

Weitere Informationen zu den wichtigsten Navigationskonzepten finden Sie in den folgenden Leitfäden:

  • Übersicht:Lesen Sie sich die allgemeine Übersicht über die Navigationskomponente durch.
  • Aktivitätsziele:Beispiele für die Implementierung von Zielen, über die Nutzer zu Aktivitäten weitergeleitet werden.
  • Dialogziele:Beispiele für die Erstellung von Zielen, über die Nutzer zu einem Dialog weitergeleitet werden.
  • Zu einem Ziel navigieren:Eine detaillierte Anleitung zum Navigieren von einem Ziel zum anderen.
  • Verschachtelte Grafiken:Eine ausführliche Anleitung zum Verschachteln eines Navigationsdiagramms in einem anderen.