o componente Navigation oferece uma linguagem específica de domínio baseada em Kotlin; ou
DSL, que depende do tipo seguro de tipos (type-safe) do Kotlin
builders
, Essa API permite compor seu gráfico de forma declarativa no código Kotlin, em vez
do que em um recurso XML. Isso pode ser útil se você deseja criar a
a navegação dinâmica. Por exemplo, o app pode fazer o download e armazenar em cache
configuração de navegação de um serviço da Web externo e, em seguida, usar essa
para criar dinamicamente um gráfico de navegação no conjunto de dados
função onCreate()
.
Dependências
Para usar a DSL do Kotlin com fragmentos, adicione a dependência abaixo ao código
Arquivo 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") }
Como criar um gráfico
Este é um exemplo básico baseado no conjunto de dados Sunflower
app. Para isso
por exemplo, temos dois destinos: home
e plant_detail
. O destino home
está presente quando o usuário inicia o app pela primeira vez. Esse destino exibe uma lista de plantas do jardim do usuário. Quando o usuário seleciona uma das plantas, o app navega para o destino plant_detail
.
A Figura 1 mostra esses destinos junto com os argumentos exigidos pelo destino plant_detail
e uma ação, to_plant_detail
, que o app usa para navegar de home
para plant_detail
.
Como hospedar um gráfico de navegação DSL do Kotlin
Antes de criar o gráfico de navegação do seu app, você precisa de um local para hospedar o
gráfico. Este exemplo usa fragmentos, então hospeda o gráfico em um
NavHostFragment
dentro de uma
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>
O atributo app:navGraph
não está definido nesse exemplo. O gráfico
não é definido como um recurso na
a pasta res/navigation
, então ela precisa ser definida como parte de onCreate()
.
processo na atividade.
Em XML, uma ação combina um ID de destino com um ou mais argumentos. No entanto, ao usar a DSL de navegação, uma rota pode conter argumentos como parte de ao longo do trajeto. Isso significa que não há conceito de ações ao usar a DSL.
A próxima etapa é definir as rotas que você usará ao definir seu gráfico.
Criar rotas para seu gráfico
Gráficos de navegação baseados em XML são analisados como parte
do processo de build do Android. Uma constante numérica é criada para cada id
.
definido no gráfico. Esses IDs estáticos gerados no tempo de build não são
disponível ao criar seu gráfico de navegação no tempo de execução, para que a DSL do Navigation
usa serializáveis
tipos em vez de
do Google Ads. Cada rota é representada por um tipo exclusivo.
Ao lidar com argumentos, eles são integrados ao conjunto de dados tipo. Isso permite que você tenha segurança de tipo para seus argumentos de navegação.
@Serializable data object Home
@Serializable data class Plant(val id: String)
Criar um gráfico com a DSL do NavGraphBuilder
Depois de definir seus trajetos, você pode criar o gráfico de navegação.
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)
}
}
Neste exemplo, dois destinos de fragmento são definidos usando o
fragment()
Função de builder de DSL. Essa função requer dois tipos
argumentos
,
Primeiro, uma classe Fragment
.
que fornece a IU para esse destino. Definir essa opção tem o mesmo efeito que
definir o atributo android:name
nos destinos de fragmento que são definidos.
usando XML.
Em segundo lugar, a rota. Precisa ser um tipo serializável que se estenda de Any
. Ela
deve conter todos os argumentos de navegação que serão usados por esse destino,
e seus tipos.
A função também aceita uma lambda opcional para outras configurações, como como rótulo de destino, bem como funções incorporadas do builder para argumentos e links diretos.
Como navegar com o gráfico DSL do Kotlin
Por fim, você pode navegar de home
para plant_detail
usando
NavController.navigate()
chamadas:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
Em PlantDetailFragment
, você pode extrair os argumentos de navegação ao receber
o atual
NavBackStackEntry
E ligando
toRoute
para receber a instância da rota.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
Se PlantDetailFragment
estiver usando um ViewModel
, acesse a instância da rota usando
SavedStateHandle.toRoute
.
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
O restante deste guia descreve elementos comuns de gráficos de navegação, destinos e como usá-los ao criar seu gráfico.
Destinos
A DSL do Kotlin oferece suporte integrado a três tipos de destino:
Fragment
, Activity
e NavGraph
, cada um com a própria
função de extensão inline disponível para criação e configuração do
destino.
Destinos de fragmento
A
fragment()
A função DSL pode ser parametrizada com a classe de fragmento para a IU e o
tipo de rota usado para identificar exclusivamente esse destino, seguido por um lambda.
na qual é possível fornecer configurações adicionais, conforme descrito em Navegação
com a seção de gráfico DSL do Kotlin.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
Destino da atividade
A
activity()
A função DSL usa um parâmetro de tipo para a rota, mas não é parametrizada para
qualquer classe de atividade de implementação. Em vez disso, defina um activityClass
opcional
uma lambda final. Essa flexibilidade permite definir um destino
uma atividade que deve ser iniciada usando um objeto implícito
intent, em que uma solicitação explícita
classe de atividade não faria sentido. Assim como nos destinos de fragmento, você também pode
configurar um rótulo, argumentos personalizados e links diretos.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
Destino do gráfico de navegação
A
navigation()
A função DSL pode ser usada para criar uma navegação aninhada
gráfico. Essa função assume um tipo
para a rota a ser atribuída a este gráfico. Ele também usa dois argumentos:
a rota do destino inicial do gráfico e um lambda para
configurar o gráfico. Os elementos válidos incluem outros destinos, argumento personalizado
tipos, links diretos e um rótulo descritivo para os
destino.
Esse rótulo pode ser útil para vincular o gráfico de navegação a componentes da IU usando o
NavigationUI
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
Compatibilidade com destinos personalizados
Se você estiver usando um novo tipo de destino
que não oferece suporte direto à DSL do Kotlin, você pode adicionar esses destinos ao
a DSL do Kotlin usando
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
Como alternativa, você também pode usar o operador unário de adição para adicionar um destino recém-construído diretamente ao gráfico:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
Como fornecer argumentos de destino
Os argumentos de destino podem ser definidos como parte da classe de rota. Eles podem ser definida da mesma forma que você faria para qualquer classe Kotlin. Os argumentos obrigatórios são definidos como tipos não anuláveis, e argumentos opcionais são definidos com valores.
O mecanismo subjacente para representar rotas e seus argumentos é a string
em nuvem. O uso de strings para modelar rotas permite que o estado da navegação seja armazenado e
restaurado do disco durante a configuração
mudanças e processo iniciado pelo sistema
da morte. Por isso,
cada argumento de navegação precisa ser serializável, ou seja, deve ter uma
que converte a representação na memória do valor do argumento em um
String
:
A serialização do Kotlin
plug-in
gera automaticamente métodos de serialização para clusters básicos
tipos quando o
A anotação @Serializable
é adicionada a um objeto.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
Como fornecer tipos personalizados
Para tipos de argumentos personalizados, é necessário fornecer uma classe NavType
personalizada. Isso
permite que você controle exatamente como o tipo é analisado em uma rota ou link direto.
Por exemplo, uma rota usada para definir uma tela de pesquisa pode conter uma classe que representa os parâmetros de pesquisa:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
Um NavType
personalizado pode ser criado desta forma:
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)
}
}
Ele pode ser usado na DSL do Kotlin como qualquer outro tipo:
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
Ao navegar até o destino, crie uma instância da rota:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
O parâmetro pode ser recebido a partir da rota no destino:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
Links diretos
Os links diretos podem ser adicionados a qualquer destino, assim como em um gráfico de navegação baseado em XML. Todos os procedimentos definidos em Como criar um link direto para um destino se aplicam ao processo de criar um link direto usando a DSL do Kotlin.
Ao criar um link direto implícito
No entanto, você não tem um recurso de navegação XML que possa ser analisado
Elementos <deepLink>
. Portanto, não é possível colocar um <nav-graph>
.
no arquivo AndroidManifest.xml
. Em vez disso, é necessário adicionar a intent
filtros à sua atividade manualmente. A intenção
filtro fornecido deve corresponder ao caminho base, ação e tipo MIME do
links diretos do seu app.
Para adicionar links diretos a um destino, chame a função deepLink
ao lambda do destino. Ele aceita a rota como um tipo parametrizado e um
parâmetro basePath
para o caminho base do URL usado para o link direto.
Você também pode adicionar uma ação e um tipo MIME usando o
deepLinkBuilder
lambda final.
O exemplo a seguir cria um URI de link direto para o destino 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 do URI
O formato URI do link direto é gerado automaticamente com base nos campos do trajeto. usando as seguintes regras:
- Os parâmetros obrigatórios são anexados como parâmetros de caminho (exemplo:
/{id}
). - Parâmetros com um valor padrão (parâmetros opcionais) são anexados como consulta
parâmetros (exemplo:
?name={name}
) - As coleções são anexadas como parâmetros de consulta (exemplo:
?items={value1}&items={value2}
) - A ordem dos parâmetros corresponde à ordem dos campos na rota.
Por exemplo, o seguinte tipo de rota:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
tem um formato de URI gerado de:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
Não há limite para o número de links diretos que podem ser adicionados. Sempre que você chama
deepLink()
,
um novo link direto é anexado a uma lista mantida para esse destino.
Limitações
O plug-in Safe Args é
incompatível com a DSL do Kotlin, porque o plug-in procura arquivos de recursos XML para
gerar classes Directions
e Arguments
.