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 dinamica. Ad esempio, l'app potrebbe scaricare e memorizzare nella cache
configurazione di navigazione da un servizio web esterno e poi usarla
per creare dinamicamente un grafico di navigazione nel pannello
Funzione onCreate()
.
Dipendenze
Per utilizzare Kotlin DSL con Fragments, aggiungi la seguente dipendenza al file
File build.gradle
:
Alla moda
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") }
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
. 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 un luogo in cui
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 è definita come risorsa
res/navigation
, quindi deve essere impostata come parte del 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 di lungo il percorso. Ciò significa che non esiste un concetto di azioni quando si utilizza la DSL.
Il passaggio successivo è definire le route da utilizzare per definire grafico.
Crea percorsi per il tuo 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
definito nel grafico. Questi ID statici generati in fase di build non sono
disponibili durante la creazione del grafico di navigazione in fase di runtime, in modo che il sistema
utilizza serializzabili
tipi anziché
ID. Ogni percorso è rappresentato da un tipo unico.
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)
Creazione di un grafico 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. L'impostazione ha lo stesso effetto
Impostazione dell'attributo android:name
sulle destinazioni dei frammenti definite
utilizzando XML.
Il secondo è il percorso. Deve essere un tipo serializzabile che si estende da Any
. it
deve contenere gli argomenti di navigazione che verranno utilizzati da questa destinazione,
e i relativi tipi.
La funzione accetta anche un lambda facoltativo per la configurazione aggiuntiva, come come etichetta di destinazione, oltre a funzioni di builder incorporate per argomenti e link diretti.
Navigazione con il grafico DSL 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
attuale
NavBackStackEntry
e le chiamate
toRoute
per ottenere l'istanza della route.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Se PlantDetailFragment
utilizza un ViewModel
, ottieni l'istanza di route utilizzando
SavedStateHandle.toRoute
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
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 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
activity()
La funzione DSL accetta un parametro di tipo per la route 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 le attività
un'attività che dovrebbe essere avviata utilizzando una
intent, in cui un'esplicita
una lezione di attività 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
navigation()
La funzione DSL può essere utilizzata per creare una navigazione nidificata
grafico. Questa funzione prende un tipo
per la route da assegnare a questo grafico. 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, un argomento personalizzato
di testo, link diretti e un'etichetta descrittiva per il
destinazione.
Questa etichetta può essere utile per associare il grafico 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 Kotlin DSL, puoi aggiungere queste destinazioni a
il 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
}
Fornitura di argomenti di destinazione
Gli argomenti della destinazione possono essere definiti come parte della classe della 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 rappresentare le route e i relativi argomenti è di tipo stringa
basato su cloud. L'uso di stringhe per creare un modello di route consente di archiviare lo stato di navigazione
ripristinato dal disco durante la configurazione
modifiche e processo avviato dal sistema
e morte. 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
.
La serie di serializzazione di Kotlin
plug-in
genera automaticamente metodi di serializzazione per
quando
L'annotazione @Serializable
è stata aggiunta a un oggetto.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Fornitura di 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, una route utilizzata per definire una schermata di ricerca potrebbe contenere una classe rappresenta i parametri di ricerca:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
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> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
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à. L'intento
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 del 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 (esempio:
/{id}
) - I parametri con un valore predefinito (parametri facoltativi) vengono aggiunti come query
parametri (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 nella 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 Kotlin DSL, in quanto il plug-in cerca i file di risorse XML
generano le classi Directions
e Arguments
.