Jetpack Compose: Navigation
Danilo Barreto
Posted on August 19, 2021
A navegação dentro de um app Android pode ser feito de várias formas. Contudo o Jetpack apresenta um facilitador que é o Navigation Component.
O Navigation Component consiste em 3 partes:
- Navjgation graph: um recurso XML que mostra graficamente todos os caminhos e destinos da sua navegação pretendida;
-
NavHost
: um container que irá exibir os destinos dos gráficos; -
NavController
: um objeto que gerencia a navegação dentro de umNavHost
e orquestra a troca de destinos e interações.
Para poder começar a usar o Navigation Component primeiro é necessário adicionar as seguintes dependências no build.gradle:
dependencies {
def nav_version = "2.3.5"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:2.4.0-alpha06"
}
Após adicionar as referências já será possível adicionar um Navigation Graph no projeto, da seguinte forma:
- Clique bom o botão direito em res;
- Vá em New > Android Resource File;
- Escolha um nome para o arquivo
- Em Resource Type escolha Navigation
Será criado um Navigation Graph vazio onde será possível adicionar os destinos e as ações necessárias. O XML deste arquivo deve se parece com algo do tipo:
<?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"
android:id="@+id/nav_graph">
</navigation>
Incluindo um NavHost
No passo seguinte precisamos incluir um NavHost em uma Activity para realizar a orquestração da navegação. Para tanto abra o XML da Activity principal e incluir o NavHost:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
.../>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
Importante:
-
android:name
contém o nome da classe da implementação do seuNavHost
(chegaremos lá); -
app:navGraph
é o nome do arquivo navigation criado no passo anterior; -
app:defaultNavHost
quando definido comotrue
indica que esse NavHost é o padrão e ele responde ao botão Back.
Adicionando Destinos
Você pode adicionar novos destinos ao Navigation Graph apontando para Fragments existentes ou criando novos.
Em um destino temos 4 atributos principais:
- id define o id do destino e como deve ser referenciado no código;
- name é caminho da classe que responde pelo código deste destino;
- label nome legível do destino;
- layout arquivo xml usado para renderizar o destino
No exemplo acima teremos um XML parecido com este:
<?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/fragmentMain">
<fragment
android:id="@+id/fragmentMain"
android:name="com.example.navcomp.FragmentMain"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_fragmentMain_to_fragmentSecond"
app:destination="@id/fragmentSecond" />
</fragment>
<fragment
android:id="@+id/fragmentThird"
android:name="com.example.navcomp.FragmentThird"
android:label="fragment_third"
tools:layout="@layout/fragment_third" />
<fragment
android:id="@+id/fragmentSecond"
android:name="com.example.navcomp.FragmentSecond"
android:label="fragment_second"
tools:layout="@layout/fragment_second" >
<action
android:id="@+id/action_fragmentSecond_to_fragmentThird"
app:destination="@id/fragmentThird" />
</fragment>
</navigation>
Um item que você deve ter notado no XML acima que não foi falado são as actions. Uma action representa uma conexão lógica entre destinos. As actions auxiliam na hora da escrita do código dizendo como e para qual destino uma action deve trafegar.
Para criar um action basta arrastar o mouse de um destino para o outro. Uma action tem os seguintes atributos notáveis:
- id contendo o id da action para ser referenciado no código;
- destination o id do destino para onde vai quando a action for executada.
A navegação é executada de fato usando um NavController
, que é um objeto que fica dentro de um NavHost
. Existem 3 formas de acessar um NavController
:
Fragment.findNavController()
View.findNavController()
-
Activity.findNavController(viewId: Int)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Agora o exemplo completo da navegação:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go To 2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go To 3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:layout_width="0dp"
android:layout_height="0dp"
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
e o MainActivity.kt
package com.example.navcomp
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
val navController = navHostFragment?.findNavController();
var button1 = findViewById<Button>(R.id.button1);
var button2 = findViewById<Button>(R.id.button2);
button1.setOnClickListener {
navController?.navigate(R.id.action_fragmentMain_to_fragmentSecond);
}
button2.setOnClickListener {
navController?.navigate(R.id.action_fragmentSecond_to_fragmentThird);
}
}
}
Esse exemplo foi bem básico. Há muito mais o que explorar como parâmetros tipados com o SafeArgs, Deep Links, Nested Graphs e outros.
Posted on August 19, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.