O componente Navigation inclui uma classe
NavigationUI
. Essa classe contém métodos estáticos que gerenciam a navegação com a barra superior
do app, a gaveta de navegação e a navegação inferior.
Barra de apps superior
A barra de apps superior (link em inglês) oferece um lugar consistente ao longo da parte de cima do app para mostrar informações e ações da tela atual.
NavigationUI
contém métodos que atualizam automaticamente o conteúdo na barra
superior à medida que os usuários navegam pelo app. Por exemplo, NavigationUI
usa os
rótulos de destino do gráfico de navegação para manter o título da barra superior
do app atualizado.
<navigation> <fragment ... android:label="Page title"> ... </fragment> </navigation>
Ao usar NavigationUI
com as principais implementações da barra de apps discutidas abaixo,
o rótulo anexado aos destinos pode ser preenchido automaticamente com os
argumentos fornecidos para o destino, usando o formato de {argName}
no
seu marcador.
NavigationUI
oferece suporte aos seguintes tipos de barra de apps:
Para ver mais informações sobre as barras de apps, consulte Configurar a barra de apps.
AppBarConfiguration
NavigationUI
usa um objeto AppBarConfiguration
para gerenciar o comportamento do botão "Navegação" no canto superior esquerdo
da área de exibição do app. O comportamento do botão "Navegação" muda quando
o usuário está em um destino de nível superior.
Um destino de nível superior é o destino raiz ou de nível mais alto em um conjunto de destinos relacionados hierarquicamente. Destinos de nível superior não exibem um botão "Para cima" na barra de apps superior porque não há destino de nível superior a eles. Por padrão, o destino inicial do app é o único destino de nível superior.
Quando o usuário está em um destino de nível superior, o botão "Navegação" se torna um
ícone de gaveta
,
se o destino usa um DrawerLayout
. Se o destino não usar um
DrawerLayout
, o botão "Navegação" ficará oculto. Quando o usuário está em qualquer outro destino, o botão "Navegação" aparece como um botão "Para cima"
.
Para configurar o botão "Navegação" usando apenas o destino inicial como o
destino de nível superior, crie um objeto AppBarConfiguration
e transmita o gráfico de navegação correspondente, como mostrado abaixo:
Kotlin
val appBarConfiguration = AppBarConfiguration(navController.graph)
Java
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
Em alguns casos, pode ser necessário definir vários destinos de nível superior em vez de
usar o destino inicial padrão. Usar um BottomNavigationView
é um
caso de uso comum para isso, em que você pode ter telas irmãs não
relacionadas hierarquicamente entre si e que podem ter o próprio conjunto de destinos
relacionados. Para casos como esses, você pode transmitir um conjunto de IDs
de destino para o construtor, como mostrado abaixo:
Kotlin
val appBarConfiguration = AppBarConfiguration(setOf(R.id.main, R.id.profile))
Java
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.main, R.id.profile).build();
Criar uma barra de ferramentas
Para criar uma barra de ferramentas com NavigationUI
, primeiro defina a barra na atividade
principal, como mostrado:
<LinearLayout> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" /> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" ... /> ... </LinearLayout>
Em seguida, chame setupWithNavController()
do método onCreate()
da atividade principal, como mostrado no exemplo
a seguir:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main) ... val navController = findNavController(R.id.nav_host_fragment) val appBarConfiguration = AppBarConfiguration(navController.graph) findViewById<Toolbar>(R.id.toolbar) .setupWithNavController(navController, appBarConfiguration) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); ... NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build(); Toolbar toolbar = findViewById(R.id.toolbar); NavigationUI.setupWithNavController( toolbar, navController, appBarConfiguration); }
Para que o botão "Navegação" seja exibido como um botão "Para cima" em todos
os destinos, transmita um conjunto vazio de IDs de destino aos destinos
de nível superior quando criar sua AppBarConfiguration
. Isso pode ser útil
se, por exemplo, você tiver uma segunda atividade que precisa exibir um botão "Para cima"
na Toolbar
em todos os destinos. Isso permite que o usuário navegue de volta
para a atividade pai quando não há outros destinos na pilha
de retorno. É possível usar
setFallbackOnNavigateUpListener()
para controlar o comportamento do substituto para quando navigateUp()
não fizer
nada, como mostrado no exemplo a seguir:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { ... val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController val appBarConfiguration = AppBarConfiguration( topLevelDestinationIds = setOf(), fallbackOnNavigateUpListener = ::onSupportNavigateUp ) findViewById<Toolbar>(R.id.toolbar) .setupWithNavController(navController, appBarConfiguration) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { ... NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder() .setFallbackOnNavigateUpListener(::onSupportNavigateUp) .build(); Toolbar toolbar = findViewById(R.id.toolbar); NavigationUI.setupWithNavController( toolbar, navController, appBarConfiguration); }
Incluir CollapsingToolbarLayout
Para incluir um CollapsingToolbarLayout
com sua barra de ferramentas, primeiro defina a
barra e o layout ao redor dela na sua atividade, como mostrado abaixo:
<LinearLayout> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="@dimen/tall_toolbar_height"> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="?attr/colorPrimary" app:expandedTitleGravity="top" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"/> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" ... /> ... </LinearLayout>
Em seguida, chame setupWithNavController()
no método onCreate
da atividade principal, como mostrado abaixo:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main) ... val layout = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar_layout) val toolbar = findViewById<Toolbar>(R.id.toolbar) val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController val appBarConfiguration = AppBarConfiguration(navController.graph) layout.setupWithNavController(toolbar, navController, appBarConfiguration) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); ... CollapsingToolbarLayout layout = findViewById(R.id.collapsing_toolbar_layout); Toolbar toolbar = findViewById(R.id.toolbar); NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build(); NavigationUI.setupWithNavController(layout, toolbar, navController, appBarConfiguration); }
Barra de ações
Para compatibilizar a navegação com a barra de ações padrão, chame
setupActionBarWithNavController()
do método onCreate()
da atividade principal, como mostrado abaixo. É necessário
declarar o AppBarConfiguration
fora de onCreate()
, já que
você também o usa ao modificar onSupportNavigateUp()
:
Kotlin
private lateinit var appBarConfiguration: AppBarConfiguration ... override fun onCreate(savedInstanceState: Bundle?) { ... val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) }
Java
AppBarConfiguration appBarConfiguration; ... @Override protected void onCreate(Bundle savedInstanceState) { ... NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build(); NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); }
Em seguida, substitua onSupportNavigateUp()
para gerenciar a navegação para cima:
Kotlin
override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() }
Java
@Override public boolean onSupportNavigateUp() { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp(); }
Compatibilidade com variações da barra de apps
Adicionar a barra superior do app à sua atividade funciona bem quando o layout da barra do app é semelhante para cada destino no app. No entanto, se a barra superior de apps muda de forma significativa em vários destinos, remova essa barra da atividade e a defina em cada fragmento de destino.
Por exemplo, um dos seus destinos pode usar uma Toolbar
padrão, enquanto
outro usa um AppBarLayout
para criar uma barra de apps mais complexa com guias, como
mostrado na Figura 2.
Para implementar esse exemplo nos fragmentos de destino usando
NavigationUI
, primeiro defina a barra de apps em cada um dos layouts de fragmento,
começando com o fragmento de destino que usa uma barra de ferramentas padrão:
<LinearLayout>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
... />
...
</LinearLayout>
Em seguida, defina o fragmento de destino que usa uma barra de apps com guias:
<LinearLayout>
<com.google.android.material.appbar.AppBarLayout
... />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
... />
<com.google.android.material.tabs.TabLayout
... />
</com.google.android.material.appbar.AppBarLayout>
...
</LinearLayout>
A lógica de configuração de navegação é a mesma para os dois fragmentos,
mas é preciso chamar
setupWithNavController()
no método onViewCreated()
de cada fragmento, em vez de inicializá-los
a partir da atividade:
Kotlin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val navController = findNavController() val appBarConfiguration = AppBarConfiguration(navController.graph) view.findViewById<Toolbar>(R.id.toolbar) .setupWithNavController(navController, appBarConfiguration) }
Java
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { NavController navController = Navigation.findNavController(view); AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build(); Toolbar toolbar = view.findViewById(R.id.toolbar); NavigationUI.setupWithNavController( toolbar, navController, appBarConfiguration); }
Vincular destinos a itens de menu
NavigationUI
também fornece assistentes para vincular destinos a componentes
de IU orientados por menu. NavigationUI
contém um método assistente,
onNavDestinationSelected()
,
que leva um MenuItem
com o
NavController
que hospeda o
destino associado. Se o id
do MenuItem
corresponder ao id
do
destino, NavController
poderá navegar para esse destino.
Por exemplo, os snippets XML abaixo definem um item de menu e um destino com
um id
comum, details_page_fragment
:
<?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" ... > ... <fragment android:id="@+id/details_page_fragment" android:label="@string/details" android:name="com.example.android.myapp.DetailsFragment" /> </navigation>
<menu xmlns:android="http://schemas.android.com/apk/res/android"> ... <item android:id="@+id/details_page_fragment" android:icon="@drawable/ic_details" android:title="@string/details" /> </menu>
Se o menu foi adicionado pelo onCreateOptionsMenu()
da atividade, por exemplo,
você pode associar os itens de menu aos destinos, modificando o
onOptionsItemSelected()
da atividade para chamar onNavDestinationSelected()
, como mostrado no
exemplo a seguir.
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { val navController = findNavController(R.id.nav_host_fragment) return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item) }
Java
@Override public boolean onOptionsItemSelected(MenuItem item) { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); return NavigationUI.onNavDestinationSelected(item, navController) || super.onOptionsItemSelected(item); }
Agora, quando um usuário clica no item de menu details_page_fragment
, o app
navega automaticamente para o destino correspondente com o mesmo id
.
Adicionar uma gaveta de navegação
A gaveta de navegação é um painel da IU que mostra o menu de navegação principal do app. A gaveta aparece quando o usuário toca no ícone da gaveta na barra de apps ou quando o usuário desliza um dedo da borda esquerda da tela.
O ícone da gaveta é exibido em todos os
destinos de nível superior que usam um DrawerLayout
.
Para adicionar uma gaveta de navegação, primeiro declare
DrawerLayout
como a visualização
raiz. Dentro de DrawerLayout
, adicione um layout para o conteúdo principal da IU e
outra visualização com o conteúdo da gaveta de navegação.
Por exemplo, o layout a seguir usa um DrawerLayout
com duas visualizações filhas: um
NavHostFragment
para o
conteúdo principal e uma
NavigationView
para o conteúdo da gaveta de navegação.
<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<!-- Container for contents of drawer - use NavigationView to make configuration easier -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true" />
</androidx.drawerlayout.widget.DrawerLayout>
Em seguida, conecte o DrawerLayout
ao gráfico de navegação, transmitindo-o para AppBarConfiguration
, como mostrado no
exemplo a seguir.
Kotlin
val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
Java
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()) .setDrawerLayout(drawerLayout) .build();
Em seguida, na classe de atividade principal, chame
setupWithNavController()
do método onCreate()
da atividade principal, como mostrado abaixo:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main) ... val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController findViewById<NavigationView>(R.id.nav_view) .setupWithNavController(navController) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); ... NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); NavigationView navView = findViewById(R.id.nav_view); NavigationUI.setupWithNavController(navView, navController); }
A partir do
Navigation 2.4.0-alpha01,
o estado de cada item de menu é salvo e restaurado quando você usa
setupWithNavController
.
Navegação inferior
NavigationUI
também pode gerenciar a navegação inferior. Quando um usuário selecionar um item
de menu, o NavController
chama
onNavDestinationSelected()
e atualiza automaticamente o item selecionado na barra de navegação inferior.
Para criar uma barra de navegação inferior no app, primeiro defina a barra na atividade principal, como mostrado abaixo:
<LinearLayout> ... <androidx.fragment.app.FragmentContainerView android:id="@+id/nav_host_fragment" ... /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" app:menu="@menu/menu_bottom_nav" /> </LinearLayout>
Em seguida, na classe de atividade principal, chame
setupWithNavController()
do método onCreate()
da atividade principal, como mostrado abaixo:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { setContentView(R.layout.activity_main) ... val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController findViewById<BottomNavigationView>(R.id.bottom_nav) .setupWithNavController(navController) }
Java
@Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); ... NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment); NavController navController = navHostFragment.getNavController(); BottomNavigationView bottomNav = findViewById(R.id.bottom_nav); NavigationUI.setupWithNavController(bottomNav, navController); }
A partir do
Navigation 2.4.0-alpha01,
o estado de cada item de menu é salvo e restaurado quando você usa
setupWithNavController
.
Para ver um exemplo abrangente que inclua a navegação inferior, consulte Amostra de Navigation avançada para Componentes da arquitetura do Android no GitHub.
Detectar eventos de navegação
Interagir com o NavController
é o principal método de navegação entre destinos. O NavController
é responsável por substituir o conteúdo do NavHost
pelo novo destino. Em muitos casos, os elementos da IU, como uma barra de apps superior ou
outros controles de navegação persistentes, como uma BottomNavigationBar
, ficam fora
do NavHost
e precisam ser atualizados à medida que você navega entre os destinos.
NavController
oferece uma interface OnDestinationChangedListener
que é
chamada quando o destino atual
do NavController
ou os argumentos dele mudam. Um novo listener pode ser registrado pelo
método
addOnDestinationChangedListener()
. Observe que, ao chamar addOnDestinationChangedListener()
, se o
destino atual existe, ele é imediatamente enviado ao seu listener.
NavigationUI
usa OnDestinationChangedListener
para tornar esses componentes de IU
comuns compatíveis com a navegação. No entanto, você também pode usar
OnDestinationChangedListener
sozinho para fazer com que qualquer IU personalizada ou a lógica
de negócios reconheça eventos de navegação.
Por exemplo, você pode ter elementos de IU comuns que devem aparecer em
algumas áreas do app e em outras não. Usando seu próprio
OnDestinationChangedListener
, você pode exibir ou ocultar esses elementos
da IU com base no destino pretendido, como mostrado no exemplo a seguir.
Kotlin
navController.addOnDestinationChangedListener { _, destination, _ -> if(destination.id == R.id.full_screen_destination) { toolbar.visibility = View.GONE bottomNavigationView.visibility = View.GONE } else { toolbar.visibility = View.VISIBLE bottomNavigationView.visibility = View.VISIBLE } }
Java
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() { @Override public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) { if(destination.getId() == R.id.full_screen_destination) { toolbar.setVisibility(View.GONE); bottomNavigationView.setVisibility(View.GONE); } else { toolbar.setVisibility(View.VISIBLE); bottomNavigationView.setVisibility(View.VISIBLE); } } });
Listeners baseados em argumentos
Como alternativa, você também pode usar argumentos com valores padrão no
gráfico de navegação, que podem ser usados pelo controlador de IU apropriado
para atualizar seu estado. Por exemplo, em vez de basear a lógica no
OnDestinationChangedListener
no ID de destino, como no exemplo
anterior, podemos criar um argumento no NavGraph
:
<?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/navigation\_graph" app:startDestination="@id/fragmentOne"> <fragment android:id="@+id/fragmentOne" android:name="com.example.android.navigation.FragmentOne" android:label="FragmentOne"> <action android:id="@+id/action\_fragmentOne\_to\_fragmentTwo" app:destination="@id/fragmentTwo" /> </fragment> <fragment android:id="@+id/fragmentTwo" android:name="com.example.android.navigation.FragmentTwo" android:label="FragmentTwo"> <argument android:name="ShowAppBar" android:defaultValue="true" /> </fragment> </navigation>
Esse argumento não é usado ao
navegar até o destino, mas
como uma maneira de anexar mais informações ao destino usando
o defaultValue
. Nesse caso, o valor indica se a barra de apps
precisa ser exibida quando estiver no destino.
Agora, é possível adicionar um OnDestinationChangedListener
no Activity
:
Kotlin
navController.addOnDestinationChangedListener { _, _, arguments -> appBar.isVisible = arguments?.getBoolean("ShowAppBar", false) == true }
Java
navController.addOnDestinationChangedListener( new NavController.OnDestinationChangedListener() { @Override public void onDestinationChanged( @NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments ) { boolean showAppBar = false; if (arguments != null) { showAppBar = arguments.getBoolean("ShowAppBar", false); } if(showAppBar) { appBar.setVisibility(View.VISIBLE); } else { appBar.setVisibility(View.GONE); } } } );
O NavController
invoca esse callback sempre que o destino de navegação mudar. O
Activity
agora pode atualizar o estado ou a visibilidade dos componentes
da IU que pertencem a ele com base nos argumentos recebidos no callback.
Uma vantagem dessa abordagem é que o Activity
vê apenas os
argumentos no gráfico de navegação e não conhece os papéis e as responsabilidades individuais
de Fragment
. Da mesma forma, os fragmentos individuais não conhecem
a Activity
contida e os componentes de IU dela.
Outros recursos
Para saber mais sobre a navegação, consulte os seguintes recursos adicionais.
Amostras
- Amostra de Navigation básica para Componentes da arquitetura do Android
- Amostra de Navigation avançada para Componentes da arquitetura do Android
Codelabs
Postagens do blog
Vídeos
- 10 práticas recomendadas para migrar para uma atividade única
- Atividade única: por que, quando e como (Conferência de Desenvolvedores Android '18)
- Android Jetpack: gerenciar a navegação da IU com o Navigation Controller (Google I/O '18)