Il componente Navigazione fornisce una lingua specifica del dominio basata su Kotlin, oppure
DSL, che si basa sulla tecnologia type-safe di Kotlin
costruttori
di Google. Questa API ti consente di comporre in modo dichiarativo il grafico nel codice Kotlin, anziché
che all'interno di una risorsa XML. Questo può essere utile se vuoi creare la navigazione della tua app in modo dinamico. Ad esempio, la tua app potrebbe scaricare e memorizzare nella cache una configurazione di navigazione da un servizio web esterno e poi utilizzare questa configurazione per creare dinamicamente un grafo di navigazione nella funzione onCreate()
della tua attività.
Dipendenze
Per utilizzare Kotlin DSL con Fragments, aggiungi la seguente dipendenza al file
File build.gradle
:
Groovy
dependencies { def nav_version = "2.9.2" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.9.2" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Creazione di un grafico
Ecco un esempio di base basato sulla Girasole
Google Cloud. Per questo
ad esempio, abbiamo due destinazioni: home
e plant_detail
. La destinazione home
è presente quando l'utente avvia l'app per la prima volta. Questa destinazione
visualizza un elenco di piante del giardino dell'utente. Quando l'utente seleziona una delle piante, l'app passa alla destinazione plant_detail
.
La figura 1 mostra queste destinazioni insieme agli argomenti richiesti dalla
plant_detail
destinazione e un'azione, to_plant_detail
, utilizzata dall'app
per navigare da home
a plant_detail
.

home
e plant_detail
, insieme a un'azione che
le collega.Hosting di un grafico di navigazione DSL Kotlin
Prima di poter creare il grafico di navigazione della tua app, devi disporre di un luogo in cui
grafico. Questo esempio utilizza i frammenti, quindi ospita il grafico in un
NavHostFragment
all'interno di un
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>
Tieni presente che l'attributo app:navGraph
non è impostato in questo esempio. Il grafico non è definito come risorsa nella cartella res/navigation
, pertanto deve essere impostato nell'ambito del processo onCreate()
nell'attività.
In XML, un'azione collega un ID destinazione a uno o più argomenti. Tuttavia, quando utilizzi il DSL di navigazione, un percorso può contenere argomenti. Ciò significa che non esiste un concetto di azioni quando si utilizza la DSL.
Il passaggio successivo consiste nel definire i percorsi che utilizzerai per definire il gráfo.
Creare percorsi per il grafico
I grafici di navigazione basati su XML vengono analizzati come parte
del processo di compilazione di Android. Viene creata una costante numerica per ogni id
attributo definito nel grafico. Questi ID statici generati in fase di compilazione non sono disponibili quando crei il grafo di navigazione in fase di esecuzione, pertanto il Navigation DSL utilizza tipi serializzabili anziché ID. Ogni percorso è rappresentato da un tipo univoco.
Quando si gestiscono argomenti, questi vengono incorporati nel percorso del testo. In questo modo puoi impostare la sicurezza del tipo per gli argomenti di navigazione.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Creare un grafo con il DSL NavGraphBuilder
Una volta definiti i percorsi, puoi creare il grafico di navigazione.
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 questo esempio, vengono definite due destinazioni di frammenti utilizzando il metodo
fragment()
Funzione di builder DSL. Questa funzione richiede due
argomenti
di Google.
Innanzitutto, un corso Fragment
.
che fornisce la UI per questa destinazione. Questa impostazione ha lo stesso effetto dell'impostazione dell'attributo android:name
sulle destinazioni dei frammenti definite utilizzando il codice XML.
Il secondo è il percorso. Deve essere un tipo serializzabile che si estende da Any
. Deve contenere tutti gli argomenti di navigazione che verranno utilizzati da questa destinazione e i relativi tipi.
La funzione accetta anche un parametro lambda facoltativo per una configurazione aggiuntiva, come l'etichetta di destinazione, nonché funzioni di creazione incorporate per argomenti personalizzati e link diretti.
Navigare con il grafico DSL di Kotlin
Infine, puoi navigare da home
a plant_detail
utilizzando
NavController.navigate()
:
chiamate:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
In PlantDetailFragment
, puoi ottenere gli argomenti di navigazione ottenendo
l'attuale
NavBackStackEntry
e chiamando
toRoute
per ottenere l'istanza del percorso.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Se PlantDetailFragment
utilizza un ViewModel
, ottieni l'istanza del route utilizzando
SavedStateHandle.toRoute
.
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Nella parte rimanente di questa guida vengono descritti gli elementi comuni dei grafici di navigazione, le destinazioni e come utilizzarli durante la creazione del grafico.
Destinazioni
La DSL Kotlin fornisce supporto integrato per tre tipi di destinazione:
Destinazioni Fragment
, Activity
e NavGraph
, ciascuna delle quali ha le proprie
funzione di estensione in linea disponibile per creare e configurare
destinazione.
Destinazioni dei frammenti
La
fragment()
La funzione DSL può essere parametrizzata con la classe del frammento per l'interfaccia utente e la
tipo di route utilizzato per identificare in modo univoco questa destinazione, seguito da una lambda
in cui puoi fornire un'ulteriore configurazione come descritto nella Navigazione
con il grafico Kotlin DSL.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Destinazione dell'attività
La funzione DSL
activity()
accetta un parametro di tipo per il percorso, ma non è parametrizzata per
qualsiasi classe di attività di implementazione. Puoi invece impostare un valore facoltativo per il campo activityClass
un lambda finale. Questa flessibilità ti consente di definire una destinazione per un'attività che deve essere avviata utilizzando un intent implicito, in cui un'attività esplicita non avrebbe senso. Come per le destinazioni dei frammenti, puoi anche configurare un'etichetta, argomenti personalizzati e link diretti.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Destinazione grafico di navigazione
La funzione
navigation()
DSL può essere utilizzata per creare un grafo di navigazione nidificato. Questa funzione accetta un parametro di tipo per il percorso da assegnare a questo grafo. Richiede anche due argomenti:
il percorso della destinazione di partenza del grafico e una lambda per
e configurare il grafico. Gli elementi validi includono altre destinazioni, tipi di argomenti personalizzati, link diretti e un'etichetta descrittiva per la destinazione.
Questa etichetta può essere utile per associare il grafo di navigazione ai componenti dell'interfaccia utente utilizzando
NavigationUI
.
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Supporto di destinazioni personalizzate
Se utilizzi un nuovo tipo di destinazione
che non supporta direttamente il DSL Kotlin, puoi aggiungere queste destinazioni al
tuo DSL Kotlin utilizzando
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
In alternativa, puoi anche utilizzare l'operatore unario più per aggiungere una nuova destinazione creata direttamente nel grafico:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Fornire gli argomenti di destinazione
Gli argomenti di destinazione possono essere definiti all'interno della classe Route. Questi possono essere esattamente come lo faresti per qualsiasi classe Kotlin. Gli argomenti obbligatori sono i tipi non nulli e gli argomenti facoltativi sono definiti con e i relativi valori.
Il meccanismo sottostante per la rappresentazione delle route e dei relativi argomenti si basa su stringhe. L'utilizzo di stringhe per modellare le route consente di memorizzare e ripristinare lo stato di navigazione dal disco durante le modifiche della configurazione e l'interruzione del processo avviata dal sistema. Per questo motivo,
ogni argomento di navigazione deve essere serializzabile, cioè deve avere
che converte la rappresentazione in memoria del valore dell'argomento in un
String
.
Il plug-in di serializzazione Kotlin genera automaticamente metodi di serializzazione per i tipi di base quando l'annotazione @Serializable
viene aggiunta a un oggetto.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Fornire tipi personalizzati
Per i tipi di argomenti personalizzati, devi fornire una classe NavType
personalizzata. Questo
ti consente di controllare esattamente il modo in cui il tipo viene analizzato da una route o un link diretto.
Ad esempio, un percorso utilizzato per definire una schermata di ricerca potrebbe contenere una classe che rappresenta i parametri di ricerca:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
@Parcelize
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Un NavType
personalizzato potrebbe essere scritto come:
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)
}
}
Questa opzione può quindi essere utilizzata nella tua DSL Kotlin come qualsiasi altro tipo:
fragment<SearchFragment, SearchRoute>(
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
) {
label = getString(R.string.plant_search_title)
}
Quando raggiungi la destinazione, crea un'istanza del percorso:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
Il parametro può essere ottenuto dalla route nella destinazione:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Link diretti
I link diretti possono essere aggiunti a qualsiasi destinazione, proprio come con un file XML grafico di navigazione. Tutte le procedure descritte nella sezione Creazione di un link diretto per una destinazione si applicano al processo di creazione di un link diretto utilizzando il Kotlin DSL.
Quando crei un link diretto implicito
Tuttavia, non hai una risorsa di navigazione XML che possa essere analizzata
<deepLink>
elementi. Pertanto, non puoi fare affidamento sul posizionamento di un <nav-graph>
nel tuo file AndroidManifest.xml
e al suo posto deve aggiungere l'intent
filtri manualmente alle tue attività. Lo scopo
che fornisci deve corrispondere al percorso di base, all'azione e al tipo MIME
link diretti dell'app.
I link diretti vengono aggiunti a una destinazione richiamando la funzione deepLink
all'interno
il lambda della destinazione. Accetta la route come tipo con parametri e un
parametro basePath
per il percorso di base dell'URL utilizzato per il link diretto.
Puoi anche aggiungere un'azione e un tipo MIME utilizzando
deepLinkBuilder
lambda finale.
L'esempio seguente crea un URI di link diretto per la destinazione 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/*"
}
}
Formato URI
Il formato dell'URI del link diretto viene generato automaticamente dai campi del percorso utilizzando le seguenti regole:
- I parametri obbligatori vengono aggiunti come parametri di percorso (ad es.
/{id}
) - I parametri con un valore predefinito (parametri facoltativi) vengono aggiunti come parametri di query (esempio:
?name={name}
). - Le raccolte vengono aggiunte come parametri di query (ad esempio:
?items={value1}&items={value2}
) - L'ordine dei parametri corrisponde all'ordine dei campi nel route
Ad esempio, il seguente tipo di route:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
ha un formato URI generato:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Non esiste un limite al numero di link diretti che puoi aggiungere. Ogni volta che chiami
deepLink()
viene aggiunto un nuovo link diretto a un elenco gestito per quella destinazione.
Limitazioni
Il plug-in Safe Args è
incompatibile con il DSL Kotlin, in quanto cerca file di risorse XML per
generare classi Directions
e Arguments
.