Die Navigationskomponente bietet eine Kotlin-basierte domainspezifische Sprache oder
DSL, das auf der typsicheren Methode von Kotlin
Builder
. Mit dieser API können Sie
Ihre Grafik deklarativ in Ihrem Kotlin-Code erstellen,
als in einer XML-Ressource. Dies kann nützlich sein, wenn Sie die
Navigation dynamisch gestalten. Ihre App könnte beispielsweise ein
von einem externen Webdienst abgerufen werden,
um dynamisch ein Navigationsdiagramm im
onCreate()
.
Abhängigkeiten
Fügen Sie zur Verwendung von Kotlin DSL mit Fragmenten die folgende Abhängigkeit zum
build.gradle
-Datei:
Groovy
dependencies { def nav_version = "2.8.4" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.4" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Diagramm erstellen
Hier ist ein einfaches Beispiel, das auf der Vorlage Sonnenblume
App. In diesem Fall
Beispiel mit zwei Zielen: home
und plant_detail
. Das home
Ziel ist vorhanden, wenn der Nutzer die App zum ersten Mal startet. Dieses Ziel
zeigt eine Liste der Pflanzen aus dem Garten der Nutzenden an. Wenn der Nutzer eine der
navigiert die App zum Ziel plant_detail
.
Abbildung 1 zeigt diese Ziele zusammen mit den für den Parameter
plant_detail
-Ziel und die von der App verwendete Aktion to_plant_detail
um von home
nach plant_detail
zu gelangen.
Kotlin-DSL-Navigationsdiagramm hosten
Bevor Sie den Navigationsdiagramm Ihrer App erstellen können, müssen Sie einen Ort zum Hosten der
Diagramm. Da in diesem Beispiel Fragmente verwendet werden, wird die Grafik
NavHostFragment
innerhalb einer
FragmentContainerView
:
<!-- activity_garden.xml -->
<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"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" />
</FrameLayout>
Beachten Sie, dass das Attribut app:navGraph
in diesem Beispiel nicht festgelegt ist. Das Diagramm
nicht als Ressource definiert,
res/navigation
-Ordner, daher muss er als Teil des onCreate()
festgelegt werden
in der Aktivität.
In XML verknüpft eine Aktion eine Ziel-ID mit einem oder mehreren Argumenten. Bei Verwendung des Navigations-DSL kann eine Route jedoch Argumente als Teil eines die Route berechnen. Das bedeutet, dass bei Verwendung von DSL kein Konzept für Aktionen vorliegt.
Im nächsten Schritt definieren Sie die Routen, die Sie bei der Definition Ihrer Diagramm.
Routen für die Grafik erstellen
XML-basierte Navigationsdiagramme werden als Teil geparst.
des Android-Build-Prozesses. Für jede id
wird eine numerische Konstante erstellt.
das in der Grafik definierte Attribut enthält. Diese zur Build-Zeit generierten statischen IDs sind
beim Erstellen des Navigationsdiagramms zur Laufzeit
verfügbar, damit die Navigations-DSL
verwendet serialisierbare
anstelle von
IDs. Jede Route wird durch einen eindeutigen Typ dargestellt.
Beim Umgang mit Argumenten sind diese in die Route integriert Typ aus. So können Sie mit der für Ihre Navigationsargumente.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Diagramm mit NavGraphBuilder DSL erstellen
Nachdem Sie Ihre Routen definiert haben, können Sie das Navigationsdiagramm erstellen.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = Home
) {
fragment<HomeFragment, Home> {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment, PlantDetail> {
label = resources.getString(R.string.plant_detail_title)
}
}
In diesem Beispiel werden zwei Fragmentziele mithilfe der
fragment()
DSL-Builder-Funktion Für diese Funktion sind zwei Typen
Argumente
.
Erstens eine Fragment
-Klasse
der die UI für dieses Ziel bereitstellt. Diese Einstellung hat denselben Effekt wie
Festlegen des Attributs android:name
für definierte Fragmentziele
mithilfe von XML.
Dann die Route. Dies muss ein serialisierbarer Typ sein, der von Any
erweitert wird. Es
alle Navigationsargumente enthalten,
die von diesem Ziel verwendet werden,
und ihre Typen.
Die Funktion akzeptiert auch eine optionale Lambda-Funktion für die zusätzliche Konfiguration, z. B. als Ziellabel sowie eingebettete Builder-Funktionen für benutzerdefinierte und Deeplinks.
Mit der Kotlin-DSL-Grafik navigieren
Schließlich können Sie von home
nach plant_detail
navigieren mit
NavController.navigate()
Anrufe:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
In PlantDetailFragment
können Sie die Navigationsargumente abrufen, indem Sie Folgendes abrufen:
die aktuelle
NavBackStackEntry
und Anrufe
toRoute
um die Routeninstanz abzurufen.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Wenn PlantDetailFragment
einen ViewModel
verwendet, rufen Sie die Routeninstanz mithilfe von
SavedStateHandle.toRoute
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Im weiteren Verlauf dieses Leitfadens werden gängige Navigationsgrafikelemente, Ziele, und wie Sie diese beim Erstellen Ihrer Grafik verwenden.
Reiseziele
Kotlin DSL bietet integrierte Unterstützung für drei Zieltypen:
Fragment
-, Activity
- und NavGraph
-Ziele, von denen jedes ein eigenes Ziel hat
Inline-Erweiterungsfunktion zum Erstellen und Konfigurieren der
Ziel.
Fragmentziele
Die
fragment()
Die DSL-Funktion kann mit der Fragmentklasse für die Benutzeroberfläche und dem
Routentyp, mit dem dieses Ziel eindeutig identifiziert wird, gefolgt von einer Lambda-Funktion
Hier können Sie zusätzliche Konfigurationen vornehmen, wie unter Navigation
durch die Kotlin-DSL-Grafik.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Ziel der Aktivität
Die
activity()
DSL-Funktion verwendet einen Typparameter für die Route, ist jedoch nicht parametrisiert.
Implementierungs-Aktivitätsklasse. Stattdessen legen Sie eine optionale activityClass
in
ein nachgestelltes Lambda. Dank dieser Flexibilität können Sie ein Aktivitätsziel
eine Aktivität, die mit einer impliziten
Intent, wobei eine explizite
macht keinen Sinn. Wie bei Fragmentzielen können Sie auch
ein Label, benutzerdefinierte Argumente und Deeplinks konfigurieren.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Ziel der Navigationsgrafik
Die
navigation()
Mit der DSL-Funktion kannst du eine verschachtelte Navigation erstellen.
Graph Diese Funktion verwendet einen Typ
-Parameter für die Route, die dieser Grafik zugewiesen werden soll. Außerdem sind zwei Argumente erforderlich:
die Route des Ausgangsorts des Diagramms und eine Lambda-Funktion zum
um das Diagramm zu konfigurieren. Gültige Elemente sind andere Ziele, benutzerdefiniertes Argument
Typen, Deeplinks und ein beschreibendes Label für die
Ziel.
Dieses Label kann nützlich sein, um das Navigationsdiagramm mithilfe von
NavigationUI
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Unterstützung benutzerdefinierter Ziele
Wenn Sie einen neuen Zieltyp verwenden
das Kotlin DSL nicht direkt unterstützt, können Sie diese Ziele
Kotlin DSL mit
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
Alternativ können Sie auch den unären Plus-Operator verwenden, um eine neue erstelltes Ziel direkt in die Grafik ein:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Zielargumente bereitstellen
Zielargumente können als Teil der Routenklasse definiert werden. Diese können wie jede andere Kotlin-Klasse definiert. Erforderliche Argumente sind als Typen definiert, die keine Nullwerte zulassen können, und optionale Argumente mit Werte.
Der zugrunde liegende Mechanismus zum Darstellen von Routen und ihren Argumenten ist ein String
basiert. Durch die Verwendung von Strings zum Modellieren von Routen kann der Navigationsstatus gespeichert und
während der Konfiguration vom Laufwerk wiederhergestellt
Änderungen und vom System initiierter Prozess
Tod. Aus diesem Grund
Jedes Navigationsargument muss serialisierbar sein, das heißt, es sollte
-Methode, die die speicherinterne Darstellung des Argumentwerts in einen
String
Die Kotlin-Serialisierung
Plug-in
generiert automatisch Serialisierungsmethoden für grundlegende
, wenn der Parameter
Die Anmerkung @Serializable
wird einem Objekt hinzugefügt.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Benutzerdefinierte Typen bereitstellen
Für benutzerdefinierte Argumenttypen müssen Sie eine benutzerdefinierte NavType
-Klasse angeben. Dieses
lässt sich genau steuern, wie Ihr Typ von einer Route oder einem Deeplink geparst wird.
Beispielsweise könnte eine Route, die zur Definition eines Suchbildschirms verwendet wird, eine Klasse enthalten, die steht für die Suchparameter:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Eine benutzerdefinierte NavType
könnte folgendermaßen geschrieben werden:
val SearchParametersType = object : NavType<SearchParameters>(
isNullableAllowed = false
) {
override fun put(bundle: Bundle, key: String, value: SearchParameters) {
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): SearchParameters {
return bundle.getParcelable(key) as SearchParameters
}
override fun serializeAsValue(value: SearchParameters): String {
// Serialized values must always be Uri encoded
return Uri.encode(Json.encodeToString(value))
}
override fun parseValue(value: String): SearchParameters {
// Navigation takes care of decoding the string
// before passing it to parseValue()
return Json.decodeFromString<SearchParameters>(value)
}
}
Dieser kann dann wie jeder andere Typ in Kotlin-DSL verwendet werden:
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
Erstellen Sie während der Navigation zum Ziel eine Instanz Ihrer Route:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Der Parameter kann aus der Route im Ziel abgerufen werden:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Deeplinks
Deeplinks können jedem Ziel hinzugefügt werden, genau wie bei einem XML-gestützten Navigationsdiagramm. Die unter Deeplink erstellen für ein Ziel auf den Prozess angewendet. wie Sie mit Kotlin DSL einen Deeplink erstellen.
Beim Erstellen eines impliziten Deeplinks
Sie haben jedoch keine XML-Navigationsressource, die analysiert werden kann,
<deepLink>
-Elemente. Daher können Sie sich nicht darauf verlassen, <nav-graph>
-Element in der Datei AndroidManifest.xml
und muss stattdessen intent hinzufügen
Filter manuell zu Ihren Aktivitäten hinzufügen. Die Absicht
Filter, den Sie angeben, sollten mit dem Basispfad, der Aktion und dem MIME-Typ
für die Deeplinks Ihrer App.
Zum Hinzufügen von Deeplinks zu einem Ziel wird die darin enthaltene Funktion deepLink
aufgerufen
die Lambda-Funktion des Ziels. Sie akzeptiert die Route als parametrisierten Typ und einen
basePath
für den Basispfad der für den Deeplink verwendeten URL.
Sie können auch eine Aktion und einen MIME-Typ hinzufügen, indem Sie die
deepLinkBuilder
hinteren Lambda.
Im folgenden Beispiel wird ein Deeplink-URI für das Ziel Home
erstellt.
@Serializable data object Home
fragment<HomeFragment, Home>{
deepLink<Home>(basePath = "www.example.com/home"){
// Optionally, specify the action and/or mime type that this destination
// supports
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
}
URI-Format
Das Deeplink-URI-Format wird automatisch aus den Feldern der Route generiert mithilfe der folgenden Regeln:
- Erforderliche Parameter werden als Pfadparameter angehängt. Beispiel:
/{id}
- Parameter mit einem Standardwert (optionale Parameter) werden als Abfrage
Parameter (Beispiel:
?name={name}
) - Sammlungen werden als Abfrageparameter angehängt. Beispiel:
?items={value1}&items={value2}
) - Die Reihenfolge der Parameter entspricht der Reihenfolge der Felder in der Route
Der folgende Routentyp:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
hat folgendes URI-Format:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Sie können beliebig viele Deeplinks hinzufügen. Bei jedem Anruf
deepLink()
wird ein neuer Deeplink an eine Liste angehängt, die für dieses Ziel verwaltet wird.
Beschränkungen
Das Plug-in Sichere Args ist
nicht mit Kotlin DSL kompatibel, da das Plug-in nach XML-Ressourcendateien sucht,
Generieren der Klassen Directions
und Arguments
.