Le composant Navigation fournit un langage spécifique à un domaine basé sur Kotlin.
le DSL, qui repose sur la protection du typage de Kotlin
constructeurs
pour en savoir plus. Cette API vous permet de composer votre graphique de manière déclarative dans votre code Kotlin,
que dans une ressource XML. Cela peut être utile si vous souhaitez créer
la navigation
de manière dynamique. Par exemple, votre application peut télécharger et mettre en cache
la configuration de navigation à partir d'un service Web externe,
pour créer dynamiquement un graphique de navigation dans le
fonction onCreate()
.
Dépendances
Pour utiliser le DSL Kotlin avec des fragments, ajoutez la dépendance suivante au fichier
Fichier build.gradle
:
Groovy
dependencies { def nav_version = "2.8.0" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.0" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Créer un graphe
Voici un exemple basique basé sur le modèle Tournesol
l'application Nest. Pour cette
Par exemple, nous avons deux destinations: home
et plant_detail
. La destination home
est présente lorsque l'utilisateur lance l'application pour la première fois. Elle affiche la liste des plantes du jardin de l'utilisateur. Lorsque l'utilisateur sélectionne l'une des plantes, l'application accède à la destination plant_detail
.
La figure 1 illustre ces destinations, ainsi que les arguments requis par la destination plant_detail
et une action, to_plant_detail
, que l'application utilise pour passer de home
à plant_detail
.
Héberger un graphe de navigation DSL Kotlin
Avant de pouvoir créer le graphique de navigation de votre application, vous avez besoin d'un emplacement pour héberger le
graphique. Cet exemple utilise des fragments. Il héberge donc le graphe dans un élément NavHostFragment
situé dans un objet 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>
Notez que l'attribut app:navGraph
n'est pas défini dans cet exemple. Le graphique
n'est pas défini comme une ressource
le dossier res/navigation
. Il doit donc être défini dans le cadre de onCreate()
dans l'activité.
En XML, une action associe un ID de destination à un ou plusieurs arguments. Toutefois, lorsque vous utilisez le langage DSL de navigation, un itinéraire peut contenir des arguments la route. Autrement dit, il n'existe pas de concept d'action lorsque vous utilisez le langage DSL.
L'étape suivante consiste à définir les routes à utiliser lorsque vous définissez votre graphique.
Créer des itinéraires pour votre graphique
Les graphiques de navigation XML sont analysés en tant que parties
du processus de compilation Android. Une constante numérique est créée pour chaque id
défini dans le graphique. Ces ID statiques générés lors de la compilation ne sont pas
disponible lorsque vous créez votre graphique de navigation au moment de l'exécution. Ainsi, le langage DSL de navigation
utilise des valeurs sérialisables
d'entraînement au lieu de
ID. Chaque itinéraire est représenté par un type unique.
Dans le cas des arguments, ceux-ci sont intégrés à la route type. Vous bénéficiez ainsi de la sûreté du typage pour vos arguments de navigation.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Créer un graphe à l'aide du langage DSL NavGraphBuilder
Une fois que vous avez défini vos itinéraires, vous pouvez créer le graphique de navigation.
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)
}
}
Dans cet exemple, deux destinations de fragment sont définies à l'aide du
fragment()
Fonction de compilateur DSL. Cette fonction requiert deux types
arguments
pour en savoir plus.
D'abord, une classe Fragment
qui fournit l'UI pour cette destination. La définition de ce paramètre a le même effet que
Définir l'attribut android:name
sur les destinations de fragment définies
au format XML.
Deuxièmement, l'itinéraire. Il doit s'agir d'un type sérialisable qui s'étend à partir de Any
. Il
doit contenir tous les arguments de navigation qui seront utilisés par cette destination,
et leurs types.
La fonction accepte également un lambda facultatif pour une configuration supplémentaire, telle que comme libellé de destination, ainsi que des fonctions de compilateur intégrées pour des les arguments et les liens profonds.
Navigation avec le graphe DSL Kotlin
Enfin, vous pouvez naviguer de home
à plant_detail
en utilisant
NavController.navigate()
appels:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
Dans PlantDetailFragment
, vous pouvez obtenir les arguments de navigation en obtenant
l'actuel
NavBackStackEntry
et appel
toRoute
pour obtenir l'instance de route.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Si PlantDetailFragment
utilise un ViewModel
, obtenez l'instance de route à l'aide de la commande
SavedStateHandle.toRoute
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Le reste de ce guide décrit les éléments courants du graphe de navigation, les destinations et leur utilisation lors de la création du graphe.
Destinations
Le langage DSL Kotlin est compatible avec trois types de destinations : Fragment
, Activity
et NavGraph
. Chacune d'elles dispose de sa propre fonction d'extension intégrée permettant sa compilation et sa configuration.
Destination "fragment"
La
fragment()
La fonction DSL peut être paramétrée avec la classe de fragment pour l'interface utilisateur et la fonction
type d'itinéraire utilisé pour identifier cette destination de manière unique, suivi d'un lambda
où vous pouvez fournir une configuration supplémentaire, comme décrit dans la section Navigation
avec votre graphique DSL Kotlin.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Destination "activity"
La
activity()
La fonction DSL utilise un paramètre de type pour la route, mais n'est pas paramétrée pour
toute implémentation de classe d'activité. À la place, vous définissez un activityClass
facultatif dans
un lambda de fin. Cette flexibilité vous permet de définir une destination d'activité
une activité qui doit être lancée à l'aide d'une commande implicite
un intent, lorsqu'un élément explicite
la classe d'activité n'aurait aucun sens. Comme pour les destinations de fragment, vous pouvez également
configurer un libellé, des arguments personnalisés et des liens profonds.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Destination "NavGraph"
La
navigation()
La fonction DSL peut être utilisée pour créer une navigation imbriquée.
graphique. Cette fonction accepte un type
pour l'itinéraire à attribuer à ce graphique. Elle utilise également deux arguments:
la route de la destination de départ du graphe et un lambda pour aller plus loin
configurer le graphe. Les éléments valides incluent les autres destinations, les arguments personnalisés
de liens profonds, ainsi qu'une étiquette descriptive
destination.
Cette étiquette peut être utile pour lier le graphique de navigation aux composants d'interface utilisateur à l'aide de
NavigationUI
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Destinations personnalisées compatibles
Si vous utilisez un nouveau type de destination
qui n'est pas directement compatible avec le DSL Kotlin, vous pouvez ajouter ces destinations
votre DSL Kotlin à l'aide de
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
Vous pouvez également utiliser l'opérateur unaire plus (+) pour ajouter une destination que vous venez de créer directement au graphe :
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Fournir des arguments de destination
Les arguments de destination peuvent être définis dans la classe d'itinéraire. Il peut s'agir de la même manière que pour n'importe quelle classe Kotlin. Les arguments obligatoires sont définis comme des types ne pouvant pas avoir une valeur nulle, et les arguments facultatifs sont définis avec valeurs.
Le mécanisme sous-jacent pour représenter les routes et leurs arguments est une chaîne
à vos clients. L'utilisation de chaînes pour modéliser les routes permet de stocker l'état de navigation et
à partir du disque lors de la configuration
modifications et le processus initié par le système
la mort. Pour cette raison,
chaque argument de navigation doit être sérialisable, c'est-à-dire qu'il doit avoir une
qui convertit la représentation en mémoire de la valeur d'argument en
String
La sérialisation Kotlin
plug-in
génère automatiquement des méthodes de sérialisation pour les modèles de base
lorsque
L'annotation @Serializable
est ajoutée à un objet.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Fournir des types personnalisés
Pour les types d'arguments personnalisés, vous devez fournir une classe NavType
personnalisée. Ce
vous permet de contrôler exactement la façon dont votre type est analysé à partir d'un itinéraire ou d'un lien profond.
Par exemple, un itinéraire utilisé pour définir un écran de recherche peut contenir une classe qui représente les paramètres de recherche:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Un élément NavType
personnalisé peut être écrit comme suit :
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)
}
}
Vous pouvez ensuite l'utiliser dans le langage DSL Kotlin comme n'importe quel autre type :
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
Lorsque vous accédez à la destination, créez une instance de votre itinéraire:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Le paramètre peut être obtenu à partir de l'itinéraire dans la destination:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Liens profonds
Des liens profonds peuvent être ajoutés à n'importe quelle destination, tout comme avec un graphe de navigation basé sur XML. Toutes les procédures définies dans la section Créer un lien profond pour une destination s'appliquent au processus de la création d'un lien profond à l'aide du langage DSL Kotlin.
Lorsque vous créez un lien profond implicite
Toutefois, vous ne disposez d'aucune ressource de navigation XML pouvant être analysée
<deepLink>
. Par conséquent, vous ne pouvez pas compter sur le placement d'un <nav-graph>
.
dans votre fichier AndroidManifest.xml
et devez ajouter à la place l'intent
des filtres à votre activité. L'intention
que vous fournissez doit correspondre au chemin d'accès de base, à l'action et au type MIME
les liens profonds de votre application.
Des liens profonds sont ajoutés à une destination en appelant la fonction deepLink
qu'il contient
le lambda de la destination. Il accepte la route en tant que type paramétré
paramètre basePath
pour le chemin de base de l'URL utilisée pour le lien profond.
Vous pouvez également ajouter une action et un type MIME à l'aide de la méthode
deepLinkBuilder
lambda de fin.
L'exemple suivant crée un URI de lien profond pour la destination Home
.
@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/*"
}
}
Format de l'URI
Le format de l'URI du lien profond est automatiquement généré à partir des champs de la route à l'aide des règles suivantes:
- Les paramètres obligatoires sont ajoutés en tant que paramètres de chemin (exemple:
/{id}
). - Les paramètres associés à une valeur par défaut (paramètres facultatifs) sont ajoutés en tant que requêtes
paramètres (exemple:
?name={name}
) - Les collections sont ajoutées en tant que paramètres de requête (exemple:
?items={value1}&items={value2}
) - L'ordre des paramètres correspond à l'ordre des champs de la route
Par exemple, le type d'itinéraire suivant:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
possède le format d'URI généré suivant:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Vous pouvez ajouter autant de liens profonds que vous le souhaitez. Chaque fois que vous appelez deepLink()
, un nouveau lien profond est ajouté à la liste correspondant à cette destination.
Limites
Le plug-in Safe Args n'est pas compatible avec le langage DSL Kotlin, car il recherche des fichiers de ressources XML pour générer les classes Directions
et Arguments
.