A navegação até um destino é feita usando um
NavController
, um objeto
que gerencia a navegação do app dentro de um NavHost
. Cada NavHost
tem o próprio
NavController
correspondente. NavController
fornece algumas maneiras diferentes de
navegar até um destino, que são descritas mais detalhadamente nas seções abaixo.
Para recuperar NavController
para um fragmento, uma atividade ou uma visualização, use um dos
seguintes métodos:
Kotlin:
Java:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
Depois de recuperar um NavController
, você pode chamar uma das sobrecargas de
navigate()
para navegar entre destinos. Cada sobrecarga é compatível com vários
cenários de navegação, conforme descrito nas seções a seguir.
Usar o Safe Args para navegar com a segurança de tipo
A maneira recomendada de navegar entre destinos é usar o plug-in Safe Args do Gradle. Esse plug-in gera classes de objetos e builders simples que permitem a navegação segura de tipos entre destinos. O Safe Args é altamente recomendado para a navegação e a transmissão de dados entre destinos.
Para adicionar Safe Args
ao seu projeto, inclua o seguinte classpath
no seu arquivo build.gradle
de nível superior:
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.5.3" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.5.3" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
Você também precisa aplicar um dos dois plug-ins disponíveis.
Para gerar um código de linguagem Java adequado para módulos Java ou Java e Kotlin mistos, adicione
esta linha ao arquivo build.gradle
do seu app ou módulo:
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
Como alternativa, para gerar o código Kotlin adequado para módulos somente Kotlin, adicione:
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
Você precisa ter android.useAndroidX=true
no
arquivo gradle.properties
, como mostrado em
Migrar para o AndroidX.
Depois de ativar o Safe Args, o código gerado contém classes e métodos para cada ação definida, bem como classes correspondentes a cada destino de envio e destino.
O Safe Args gera uma classe para cada destino de origem de uma ação. O
nome da classe gerada adiciona "Directions" ao nome da classe de destino
de origem. Por exemplo, se o destino de origem tem o nome de
SpecifyAmountFragment
, a classe gerada será chamada
SpecifyAmountFragmentDirections
.
A classe gerada contém um método estático para cada ação definida no
destino de origem. Esse método usa qualquer
parâmetro de ação definido como argumentos e
retorna um objeto NavDirections
que você pode transmitir diretamente para
navigate()
.
Exemplo de Safe Args
Como exemplo, vamos supor que temos um gráfico de navegação com uma única ação que
conecta dois destinos, SpecifyAmountFragment
e ConfirmationFragment
.
O ConfirmationFragment
usa um único parâmetro float
fornecido
como parte da ação.
O Safe Args gera uma classe SpecifyAmountFragmentDirections
com um único
método, actionSpecifyAmountFragmentToConfirmationFragment()
, e uma classe interna
chamada ActionSpecifyAmountFragmentToConfirmationFragment
. A classe
interna é derivada de NavDirections
e armazena o ID de ação associado e o parâmetro
float
. O objeto NavDirections
retornado pode ser transmitido
diretamente para navigate()
, conforme mostrado no exemplo a seguir.
Kotlin
override fun onClick(v: View) { val amount: Float = ... val action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount) v.findNavController().navigate(action) }
Java
@Override public void onClick(View view) { float amount = ...; action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount); Navigation.findNavController(view).navigate(action); }
Para ver mais informações sobre como transmitir dados entre destinos com o Safe Args, consulte Usar o Safe Args para transmitir dados com segurança de tipo.
Navegar usando ID
navigate(int)
usa o ID do recurso de uma ação ou um destino. O snippet de código a seguir
mostra como navegar até ViewTransactionsFragment
.
Kotlin
viewTransactionsButton.setOnClickListener { view -> view.findNavController().navigate(R.id.viewTransactionsAction) }
Java
viewTransactionsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Navigation.findNavController(view).navigate(R.id.viewTransactionsAction); } });
Para os botões, você também pode usar o método de conveniência
createNavigateOnClickListener()
da classe
Navigation
para navegar até um destino, conforme mostrado no exemplo
a seguir.
Kotlin
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))
Java
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
Para gerenciar com outros componentes comuns de IU, por exemplo, a barra de apps superior e a navegação inferior, consulte Atualizar componentes de IU com NavigationUI.
Fornecer opções de navegação para ações
Quando você define uma ação no gráfico de navegação, a navegação gera uma
classe NavAction
correspondente,
que contém as configurações definidas para essa ação,
incluindo:
- Destino: o ID do recurso do destino.
- Argumentos padrão:
um
android.os.Bundle
contendo valores padrão para o destino, se fornecido. - Opções de navegação:
opções de navegação, representadas como
NavOptions
. Essa classe contém toda a configuração especial para a transição para e de volta do destino, incluindo a configuração do recurso de animação, o comportamento de destaque e se o destino precisa ser iniciado no modo superior único.
Vamos dar uma olhada em um gráfico de exemplo que consiste em duas telas com uma ação para navegar de uma para outra:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/a">
<fragment android:id="@+id/a"
android:name="com.example.myapplication.FragmentA"
android:label="a"
tools:layout="@layout/a">
<action android:id="@+id/action_a_to_b"
app:destination="@id/b"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
</fragment>
<fragment android:id="@+id/b"
android:name="com.example.myapplication.FragmentB"
android:label="b"
tools:layout="@layout/b">
<action android:id="@+id/action_b_to_a"
app:destination="@id/a"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"
app:popUpTo="@+id/a"
app:popUpToInclusive="true"/>
</fragment>
</navigation>
Quando o gráfico de navegação é aumentado, essas ações são analisadas, e
os objetos NavAction
correspondentes são gerados com as configurações definidas
no gráfico. Por exemplo, action_b_to_a
é definido como a navegação do
destino b
para o destino a
. A ação inclui animações com o comportamento
popTo
que remove todos os destinos da pilha de retorno. Todas essas
configurações são capturadas como NavOptions
e anexadas a NavAction
.
Para acompanhar esse NavAction
, use NavController.navigate()
, passando o ID da
ação, conforme mostrado no exemplo a seguir.
Kotlin
findNavController().navigate(R.id.action_b_to_a)
Java
NavigationHostFragment.findNavController(this).navigate(R.id.action_b_to_a);
Navegar usando DeepLinkRequest
Você pode usar
navigate(NavDeepLinkRequest)
para navegar diretamente para um
destino de link direto implícito,
conforme mostrado no exemplo a seguir.
Kotlin
val request = NavDeepLinkRequest.Builder .fromUri("android-app://androidx.navigation.app/profile".toUri()) .build() findNavController().navigate(request)
Java
NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://androidx.navigation.app/profile")) .build() NavHostFragment.findNavController(this).navigate(request)
Além de Uri
,
NavDeepLinkRequest
também é compatível com links diretos com ações e tipos MIME. Para adicionar uma ação à
solicitação, use
fromAction()
ou
setAction()
.
Para adicionar um tipo MIME a uma solicitação, use
fromMimeType()
ou
setMimeType()
.
Para que um NavDeepLinkRequest
corresponda corretamente a um destino de link direto implícito,
o URI, a ação e o tipo MIME precisam corresponder a NavDeepLink
no
destino. Os URIs precisam corresponder ao padrão, as ações precisam ser uma correspondência exata
e os tipos MIME precisam estar relacionados. Por exemplo, correspondências "imagem/jpg" com "imagem/*".
Ao contrário da navegação usando IDs de ação ou de destino, você pode navegar para qualquer link direto no seu gráfico, independentemente de o destino estar visível ou não. Você pode navegar para um destino no gráfico atual ou para um destino em um gráfico completamente diferente.
Ao navegar usando NavDeepLinkRequest
, a pilha de retorno não é redefinida. Esse
comportamento é diferente de outras
navegações de link direto, em que a
pilha de retorno é substituída durante a navegação. popUpTo
e popUpToInclusive
ainda removem destinos da pilha de retorno como se você tivesse
navegado usando um ID.
Navegação e a pilha de retorno
O Android mantém uma pilha de retorno
que contém os destinos visitados. O primeiro destino do seu app
é colocado na pilha quando o usuário abre o app. Cada chamada para o método
navigate()
coloca outro destino no topo da pilha. Tocar em Up ou Back
chama os métodos
NavController.navigateUp()
e NavController.popBackStack()
,
respectivamente, para remover (ou retirar) o destino superior da
pilha.
NavController.popBackStack()
retorna um valor booleano que indica se ele
retornou para outro destino. O caso mais comum de
retorno de false
é quando você destaca manualmente o destino inicial do seu gráfico.
Quando o método retorna false
, NavController.getCurrentDestination()
retorna
null
. Você é responsável por navegar para um novo destino ou
por manipular o menu pop-up chamando finish()
na sua atividade, conforme mostrado no
exemplo a seguir.
Kotlin
... if (!navController.popBackStack()) { // Call finish() on your Activity finish() }
Java
... if (!navController.popBackStack()) { // Call finish() on your Activity finish(); }
popUpTo e popUpToInclusive
Ao navegar usando uma ação, você também pode retirar destinos adicionais da pilha de retorno. Por exemplo, se o app tiver um fluxo de login inicial, assim que um usuário tiver feito login, todos os destinos relacionados ao login precisarão ser removidos da pilha de retorno para que o botão" "Voltar" não retorne os usuários ao fluxo de login.
Para inserir destinos ao navegar de um destino para outro, adicione um atributo
app:popUpTo
ao elemento <action>
associado. app:popUpTo
instrui a biblioteca de navegação a remover alguns destinos da pilha de retorno como
parte da chamada para navigate()
. O valor do atributo é o ID do destino mais
recente que precisa permanecer na pilha.
Você também pode incluir app:popUpToInclusive="true"
para indicar que o destino especificado em app:popUpTo
também precisa ser removido da
pilha de retorno.
Exemplo de popUpTo: lógica circular
Digamos que seu app tenha três destinos (A, B e C), juntamente com ações que levam de A a B, B a C e C de volta a A. O gráfico de navegação correspondente é mostrado na Figura 1:
Figura 1. Um gráfico de navegação circular com três destinos: A, B e C.
Em cada ação de navegação, um destino é adicionado à pilha de retorno. Se você
navegasse várias vezes por esse fluxo, sua pilha de retorno
conteria vários conjuntos de cada destino (A, B, C, A, B, C, A e assim por diante).
Para evitar essa repetição, você pode especificar app:popUpTo
e
app:popUpToInclusive
na ação que leva do destino C para
o destino A, conforme mostrado no exemplo a seguir.
<fragment android:id="@+id/c" android:name="com.example.myapplication.C" android:label="fragment_c" tools:layout="@layout/fragment_c"> <action android:id="@+id/action_c_to_a" app:destination="@id/a" app:popUpTo="@+id/a" app:popUpToInclusive="true"/> </fragment>
Depois de chegar ao destino C, a pilha de retorno contém uma instância de
cada destino (A, B, C). Ao navegar de volta ao destino A, também popUpTo
A, o que significa que removemos B e C da pilha ao navegar. Com
app:popUpToInclusive="true"
, também retiramos primeiro A da pilha,
apagando-o. Se você não usar
app:popUpToInclusive
, a pilha de retorno terá duas instâncias do
destino A.