O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.

Atualizar componentes da IU com NavigationUI

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 superior do app

A barra superior do app oferece um lugar consistente ao longo da parte superior do app para exibir informações e ações da tela atual.

tela exibindo uma barra de apps superior
Figura 1. Uma tela exibindo uma barra de apps superior.

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 é compatível com os 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 tornará um ícone de gaveta se o destino usar 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 abaixo:

<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);
}

Incluir CollapsingToolbarLayout

Para incluir um CollapsingToolbarLayout com sua barra de ferramentas, primeiro defina a barra de ferramentas e o layout ao redor da 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 mudar de forma significativa em vários destinos, considere remover essa barra da atividade e defini-la em cada fragmento de destino.

Por exemplo, um dos seus destinos pode usar um Toolbar padrão, enquanto outro usa um AppBarLayout para criar uma barra de apps mais complexa com guias, como mostrado na figura 2.

duas variações da barra de apps; uma barra de ferramentas padrão à esquerda e um
            appbarlayout com uma barra de ferramentas e guias à direita
Figura 2. Duas variações da barra de apps. À esquerda, um Toolbar padrão. À direita, um AppBarLayout com um Toolbar e guias.

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ê poderá 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 clicar no item de menu details_page_fragment, o app navegará 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.

uma gaveta aberta exibindo um menu de navegação
Figura 3. Uma gaveta aberta que exibe um menu de navegação.

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: uma 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);
}

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.

barra de navegação inferior
Figura 4. Uma 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);
}

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 superior de apps ou outros controles de navegação persistentes, como um BottomNavigationBar, vivem 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 de NavController ou dos argumentos dele mudam. Um novo listener pode ser registrado pelo método addOnDestinationChangedListener(). Observe que, ao chamar addOnDestinationChangedListener(), se o destino atual existir, ele será 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 pretende exibir em algumas áreas do app e ocultar em outras. 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);
       }
   }
});

Outros recursos

Para saber mais sobre a navegação, consulte os seguintes recursos adicionais.

Amostras

Codelabs

Postagens do blog

Vídeos