Il componente Navigazione fornisce una lingua specifica del dominio basata su Kotlin, oppure
DSL, che si basa sulla tecnologia
generatori sicuri per il tipo.
Questa API ti consente di comporre in modo dichiarativo il grafico nel codice Kotlin,
anziché all'interno di una risorsa XML. Questo può essere utile se vuoi creare
la navigazione dell'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 usare
questa configurazione per creare dinamicamente un grafico di navigazione nel
Funzione onCreate()
.
Dipendenze
Per utilizzare la DSL Kotlin, aggiungi la seguente dipendenza al parametro
File build.gradle
:
Alla moda
dependencies { def nav_version = "2.7.7" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.7.7" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
Creazione di un grafico
Iniziamo con un esempio di base basato
App Sunflower. Per questo
ad esempio, abbiamo due destinazioni: home
e plant_detail
. home
è presente quando l'utente avvia l'app per la prima volta. Questa destinazione
mostra un elenco di piante del giardino dell'utente. Quando l'utente seleziona uno di
piante, l'app raggiunge la 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
.
Hosting di un grafico di navigazione DSL Kotlin
Prima di poter creare il grafico di navigazione della tua app, devi disporre di una posizione
nel grafico. Questo esempio utilizza frammenti, quindi ospita il grafo in una
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 in questo esempio l'attributo app:navGraph
non è impostato. Il grafico
non è definito come
resource nel
res/navigation
quindi deve essere impostata come parte di onCreate()
processo nell'attività.
In XML, un'azione collega un ID destinazione a uno o più argomenti. Tuttavia, quando utilizzi la navigazione DSL, una route può contenere argomenti come parte lungo il percorso. Ciò significa che non esiste un concetto di azioni quando si utilizza la DSL.
Il passaggio successivo consiste nel definire alcune costanti da utilizzare per definire nel grafico.
Creare costanti per il grafico
Grafici di navigazione basati su XML
vengono analizzati come parte del processo di compilazione di Android. Viene creata una costante numerica
per ogni attributo id
definito nel grafico. Queste immagini statiche generate in tempo di build
Gli ID non sono disponibili durante la creazione del grafico di navigazione in fase di runtime, quindi
Navigazione DSL utilizza stringhe di route anziché ID. Ogni percorso è rappresentato da
una stringa univoca ed è buona norma definirle come costanti per ridurre
il rischio di errori di battitura.
Quando si tratta di argomenti, questi sono incorporato nella stringa della route. L'integrazione di questa logica nella route può, ancora una volta, ridurre il rischio di si insinuano bug legati agli errori di battitura.
object nav_routes {
const val home = "home"
const val plant_detail = "plant_detail"
}
object nav_arguments {
const val plant_id = "plant_id"
const val plant_name = "plant_name"
}
Creazione di un grafico con il DSL NavGraphBuilder
Una volta definite le costanti, puoi creare la navigazione grafico.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = nav_routes.home
) {
fragment<HomeFragment>(nav_routes.home) {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment>("${nav_routes.plant_detail}/{${nav_arguments.plant_id}}") {
label = resources.getString(R.string.plant_detail_title)
argument(nav_arguments.plant_id) {
type = NavType.StringType
}
}
}
In questo esempio, il lambda finale definisce due destinazioni di frammenti utilizzando il comando
fragment()
Funzione di builder DSL. Questa funzione richiede una stringa di route per la destinazione
che si ottiene dalle costanti. La funzione accetta anche un'istanza
lambda per una configurazione aggiuntiva, come l'etichetta di destinazione, nonché
le funzioni del builder incorporate per argomenti e link diretti.
La classe Fragment
che
gestisce l'interfaccia utente di ogni destinazione che viene passata come tipo con parametri all'interno
parentesi angolari (<>
). Ha lo stesso effetto dell'impostazione di android:name
sulle destinazioni dei frammenti definite utilizzando XML.
Navigazione con il grafico DSL Kotlin
Infine, puoi navigare da home
a plant_detail
utilizzando
NavController.navigation()
chiamate:
private fun navigateToPlant(plantId: String) {
findNavController().navigate("${nav_routes.plant_detail}/$plantId")
}
In PlantDetailFragment
, puoi ottenere il valore dell'argomento come mostrato
nel seguente esempio:
val plantId: String? = arguments?.getString(nav_arguments.plant_id)
I dettagli su come fornire gli argomenti durante la navigazione sono disponibili nella fornisci argomenti di destinazione.
Il resto della guida descrive gli elementi comuni dei grafici di navigazione, le destinazioni e come utilizzarle 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 nella classe del frammento di implementazione e prende una
stringa di route univoca da assegnare a questa destinazione, seguita da una lambda in cui
puoi fornire un'ulteriore configurazione, come descritto
Navigazione con il grafico Kotlin DSL
.
fragment<FragmentDestination>(nav_routes.route_name) {
label = getString(R.string.fragment_title)
// arguments, deepLinks
}
Destinazione dell'attività
La activity()
La funzione DSL prende una stringa di route univoca per assegnare la destinazione a questa destinazione, ma
non parametri in nessuna classe di attività di implementazione. Puoi invece impostare
activityClass
facoltativo in un lambda finale. Questa flessibilità ti consente di
definire una destinazione per un'attività che deve essere avviata utilizzando un
intent implicito, per cui
una classe di attività esplicita non ha senso. Come per le destinazioni dei frammenti,
puoi anche configurare un'etichetta, argomenti e link diretti.
activity(nav_routes.route_name) {
label = getString(R.string.activity_title)
// arguments, deepLinks...
activityClass = ActivityDestination::class
}
Destinazione grafico di navigazione
La navigation()
La funzione DSL può essere utilizzata per creare una
grafico di navigazione nidificato:
Questa funzione accetta tre argomenti: una route a
assegnare al grafico il percorso della destinazione di partenza del grafico e una
lambda per configurare ulteriormente il grafico. Gli elementi validi includono altre destinazioni,
argomenti, link diretti e un
etichetta descrittiva della destinazione.
Questa etichetta può essere utile per associare il grafico di navigazione all'interfaccia utente.
componenti utilizzando
UI di navigazione
navigation("route_to_this_graph", nav_routes.home) {
// label, other destinations, deep links
}
Supporto di destinazioni personalizzate
Se utilizzi un
nuovo tipo di destinazione che non
il supporto diretto per Kotlin DSL, puoi aggiungere queste destinazioni al tuo
DSL con 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
}
Fornitura di argomenti di destinazione
Qualsiasi destinazione può definire argomenti facoltativi o obbligatori. Azioni
può essere definito utilizzando
argument()
funzione su NavDestinationBuilder
, che è la classe base per tutte
del generatore di destinazioni. Questa funzione prende il nome dell'argomento come stringa
e una funzione lambda utilizzata per costruire e configurare
NavArgument
All'interno di lambda puoi specificare il tipo di dati dell'argomento, un valore predefinito se applicabile e se è o meno null.
fragment<PlantDetailFragment>("${nav_routes.plant_detail}/{${nav_arguments.plant_id}}") {
label = getString(R.string.plant_details_title)
argument(nav_arguments.plant_id) {
type = NavType.StringType
defaultValue = getString(R.string.default_plant_id)
nullable = true // default false
}
}
Se viene specificato un valore defaultValue
, è possibile dedurre il tipo. Se viene usato sia un defaultValue
e type
, i tipi devono corrispondere. Consulta le
documentazione di riferimento di NavType per un
un elenco completo dei tipi di argomenti disponibili.
Fornitura di tipi personalizzati
Alcuni tipi, ad esempio
ParcelableType
e
SerializableType
,
non supportano l'analisi dei valori delle stringhe utilizzate da route o link diretti.
perché non fanno affidamento sulla riflessione in fase di runtime. Fornendo un modello di
NavType
, puoi controllare esattamente il modo in cui il tipo viene analizzato da una route
link diretto. Ciò consente di utilizzare
Serializzazione di Kotlin o altro
per fornire la codifica e la decodifica senza riflessioni del tuo tipo personalizzato.
Ad esempio, una classe di dati che rappresenta i parametri di ricerca trasmessi al tuo
schermata di ricerca potrebbe implementare sia Serializable
(per fornire il
codifica/decodifica) e Parcelize
(per supportare il salvataggio e il ripristino
da un Bundle
):
@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>(nav_routes.plant_search) {
label = getString(R.string.plant_search_title)
argument(nav_arguments.search_parameters) {
type = SearchParametersType
defaultValue = SearchParameters("cactus", emptyList())
}
}
NavType
include sia la scrittura che la lettura di ogni campo,
significa che devi usare NavType
anche quando accedi alla
per assicurarti che i formati corrispondano:
val params = SearchParameters("rose", listOf("available"))
val searchArgument = SearchParametersType.serializeAsValue(params)
navController.navigate("${nav_routes.plant_search}/$searchArgument")
Il parametro può essere ottenuto dagli argomenti nella destinazione:
val params: SearchParameters? = arguments?.getParcelable(nav_arguments.search_parameters)
Link diretti
I link diretti possono essere aggiunti a qualsiasi destinazione, proprio come con un file XML grafico di navigazione. Tutte le stesse procedure definite Creazione di un link diretto per una destinazione si applicano al processo di creazione link diretto esplicito utilizzando 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 file AndroidManifest.xml
e deve invece aggiungere
filtri di intent manuali alla tua attività.
Il filtro per intent fornito deve corrispondere al pattern URL di base, all'azione e
tipo MIME dei link diretti dell'app.
Puoi fornire un valore deeplink
più specifico per ogni singolo link diretto
di destinazione utilizzando
deepLink()
Funzione DSL. Questa funzione accetta un NavDeepLink
che contiene un String
che rappresenta il pattern URI, String
che rappresenta le azioni dell'intent e
String
che rappresenta il mimeType .
Ad esempio:
deepLink {
uriPattern = "http://www.example.com/plants/"
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
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.
Uno scenario di link diretti impliciti più complesso che definisce anche i parametri basati su query sono riportati di seguito:
val baseUri = "http://www.example.com/plants"
fragment<PlantDetailFragment>(nav_routes.plant_detail) {
label = getString(R.string.plant_details_title)
deepLink(navDeepLink {
uriPattern = "${baseUri}/{id}"
})
deepLink(navDeepLink {
uriPattern = "${baseUri}/{id}?name={plant_name}"
})
}
Puoi utilizzare interpolazione di stringhe per semplificarne la definizione.
Limitazioni
Il plug-in Safe Args
incompatibile con il Kotlin DSL, in quanto il plug-in cerca i file di risorse XML
generano le classi Directions
e Arguments
.
Scopri di più
Consulta la sezione Sicurezza del tipo di navigazione per scoprire come garantire la sicurezza dei tipi per il tuo DSL Kotlin e Codice di Navigazione Compose.