Como usar a AppBar

A barra de apps superior proporciona um lugar consistente na parte superior da janela do app para exibir informações e ações da tela atual.

Exemplo de barra de apps superior
Figura 1. Exemplo de barra de apps superior.

A propriedade da barra de apps varia de acordo com as necessidades do seu app. Ao usar fragmentos, a barra de apps pode ser implementada como uma ActionBar que pertence à atividade do host ou a uma barra de ferramentas no layout do fragmento.

Se todas as suas telas usam a mesma barra de apps que está sempre na parte de cima e se estende pela largura da tela, use uma barra de ações fornecida pelo tema e hospedada pela atividade. O uso de barras de apps com temas ajuda a manter uma aparência consistente e oferece um local para hospedar menus de opção e um botão "para cima".

Use uma barra de ferramentas hospedada pelo fragmento se você quiser ter mais controle sobre o tamanho, a posição e a animação da barra de apps em várias telas. Por exemplo, talvez você precise de uma barra de apps recolhível ou de uma que se estenda apenas até a metade da tela e seja centralizada verticalmente.

Diferentes situações exigem diferentes abordagens para aspectos como inflação de menus e resposta à interação do usuário. Entender as diferentes abordagens e usar a melhor para o app poupa tempo e ajuda a garantir que o app funcione corretamente.

Os exemplos neste tópico se referem a um ExampleFragment que contém um perfil editável. O fragmento infla o menu definido por XML abaixo na barra de apps:

<!-- sample_menu.xml -->
<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_settings"
        android:icon="@drawable/ic_settings"
        android:title="@string/settings"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/action_done"
        android:icon="@drawable/ic_done"
        android:title="@string/done"
        app:showAsAction="ifRoom|withText"/>

</menu>

O menu contém duas opções: uma para navegar até uma tela de perfil e outra para salvar as mudanças feitas no perfil.

Barra de apps da atividade

A barra de apps geralmente é de propriedade da atividade do host. Quando a barra de apps pertence a uma atividade, os fragmentos podem interagir com ela substituindo os métodos de framework que são chamados durante a criação de fragmentos.

Registrar com atividades

Informe ao sistema que o fragmento da barra de apps está participando do preenchimento do menu de opções. Para fazer isso, chame setHasOptionsMenu(true) no método onCreate(Bundle) do fragmento, conforme mostrado no exemplo a seguir:

Kotlin

class ExampleFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }
}

Java

public class ExampleFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }
}

setHasOptionsMenu(true) informa ao sistema que seu fragmento quer receber callbacks relacionados ao menu. Quando ocorre um evento relacionado a um menu, como um clique, o método de processamento de eventos é chamado primeiro na atividade antes de ser chamado no fragmento.

No entanto, não confie nessa ordem na lógica do aplicativo. Se a mesma atividade hospeda vários fragmentos, cada fragmento pode fornecer opções de menu. Nesse caso, a ordem dos callbacks depende da ordem em que os fragmentos são adicionados.

Inflar o menu

Para mesclar seu menu ao menu de opções da barra de apps, substitua onCreateOptionsMenu() no seu fragmento. Esse método recebe o menu da barra de apps atual e um MenuInflater como parâmetros. Use o inflador de menu para criar uma instância do menu do fragmento e mescle-a no menu atual, como mostrado no exemplo a seguir:

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.sample_menu, menu)
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
       inflater.inflate(R.menu.sample_menu, menu);
    }
}

A Figura 2 mostra o menu atualizado.

O menu de opções agora contém seu fragmento do menu
Figura 2. O menu de opções agora contém seu fragmento do menu.

Processar eventos de clique

Todas as atividades e fragmentos que participam do menu de opções podem responder aos toques. O onOptionsItemSelected() do fragmento recebe o item de menu selecionado como um parâmetro e retorna um booleano para indicar se o toque foi consumido. Quando uma atividade ou um fragmento retorna true de onOptionsItemSelected(), nenhum outro fragmento participante recebe o callback.

Na sua implementação de onOptionsItemSelected(), use uma instrução switch no itemId do item do menu. Se o item selecionado for seu, processe o toque de maneira adequada e retorne true para indicar que o evento de clique foi processado. Se o item selecionado não for seu, chame a implementação de super. Por padrão, a implementação de super retorna false para permitir que o processamento do menu continue.

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.action_settings -> {
                // Navigate to settings screen.
                true
            }
            R.id.action_done -> {
                // Save profile changes.
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_settings:  {
                // Navigate to settings screen.
                return true;
            }
            case R.id.action_done: {
                // Save profile changes.
                return true;
            }
            default:
                return super.onOptionsItemSelected(item);
        }

    }

}

Modificar o menu de forma dinâmica

Coloque a lógica para ocultar ou mostrar um botão ou mudar o ícone em onPrepareOptionsMenu(). Esse método é chamado logo antes de mostrar o menu.

Continuando com o exemplo anterior, o botão Salvar ficará invisível até que o usuário inicie a edição e desaparecerá depois que o usuário salvar. A adição dessa lógica a onPrepareOptionsMenu() garante que o menu seja apresentado corretamente:

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onPrepareOptionsMenu(menu: Menu){
        super.onPrepareOptionsMenu(menu)
        val item = menu.findItem(R.id.action_done)
        item.isVisible = isEditing
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public void onPrepareOptionsMenu(@NonNull Menu menu) {
        super.onPrepareOptionsMenu(menu);
        MenuItem item = menu.findItem(R.id.action_done);
        item.setVisible(isEditing);
    }
}

Quando você precisar atualizar o menu, como quando um usuário pressiona o botão Editar para editar as informações do perfil, chame invalidateOptionsMenu() na atividade do host para solicitar que o sistema chame onCreateOptionsMenu(). Após a invalidação, é possível fazer as atualizações em onCreateOptionsMenu(). Depois que o menu é inflado, o sistema chama onPrepareOptionsMenu() e atualiza o menu para refletir o estado atual do fragmento.

Kotlin

class ExampleFragment : Fragment() {
    ...
    fun updateOptionsMenu() {
        isEditing = !isEditing
        requireActivity().invalidateOptionsMenu()
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    public void updateOptionsMenu() {
        isEditing = !isEditing;
        requireActivity().invalidateOptionsMenu();
    }
}

Barra de apps do fragmento

Se a maioria das telas do seu app não precisar de uma barra de apps ou se uma tela precisar de uma barra diferente das outras, adicione uma Toolbar ao layout do fragmento. Embora você possa adicionar uma Toolbar em qualquer lugar dentro da hierarquia de visualização do fragmento, ela geralmente é mantida na parte de cima da tela. Para usar a Toolbar no seu fragmento, forneça um ID e extraia uma referência a ele no fragmento, da mesma forma que você faria com qualquer outra visualização. Você também pode animar a barra de ferramentas usando comportamentos CoordinatorLayout.

<androidx.appcompat.widget.Toolbar
    android:id="@+id/myToolbar"
    ... />

Ao usar uma barra de apps de um fragmento, o Google recomenda usar as APIs Toolbar diretamente. Não use setSupportActionBar() e as APIs de menu do Fragment, que são adequadas apenas para barras de apps de atividades.

Inflar o menu

O método de conveniência inflateMenu(int) da Toolbar usa o ID de um recurso de menu como parâmetro. Para inflar um recurso de menu XML na barra de ferramentas, transmita o resId para esse método, conforme mostrado no exemplo a seguir:

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        viewBinding.myToolbar.inflateMenu(R.menu.sample_menu)
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        ...
        viewBinding.myToolbar.inflateMenu(R.menu.sample_menu);
    }

}

Para inflar outro recurso de menu XML, chame o método novamente com o resId do novo menu. Os novos itens são adicionados ao menu, e os itens existentes não são modificados nem removidos.

Se você quiser substituir o conjunto de menus existente, limpe o menu antes de chamar inflateMenu(int) com o novo ID do menu, como mostrado no exemplo abaixo:

Kotlin

class ExampleFragment : Fragment() {
    ...
    fun clearToolbarMenu() {
        viewBinding.myToolbar.menu.clear()
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    public void clearToolbarMenu() {

        viewBinding.myToolbar.getMenu().clear()

    }

}

Processar eventos de clique

Você pode transmitir um OnMenuItemClickListener diretamente à barra de ferramentas usando o método setOnMenuItemClickListener(). Esse listener é invocado quando o usuário seleciona um item de menu nos botões de ação apresentados no final da barra de ferramentas ou no overflow associado. O MenuItem selecionado é transmitido ao método onMenuItemClick() do listener e pode ser usado para consumir a ação, conforme mostrado no exemplo abaixo:

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        viewBinding.myToolbar.setOnMenuItemClickListener {
            when (it.itemId) {
                R.id.action_settings -> {
                    // Navigate to settings screen.
                    true
                }
                R.id.action_done -> {
                    // Save profile changes.
                    true
                }
                else -> false
            }
        }
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        ...
        viewBinding.myToolbar.setOnMenuItemClickListener(item -> {
            switch (item.getItemId()) {
                case R.id.action_settings:
                    // Navigate to settings screen.
                    return true;
                case R.id.action_done:
                    // Save profile changes.
                    return true;
                default:
                    return false;
            }
        });
    }
}

Modificar o menu de forma dinâmica

Quando o fragmento pertence à barra de apps, é possível modificar o Toolbar durante a execução como qualquer outra visualização.

Continuando com o exemplo anterior, a opção de menu Salvar ficará invisível até o usuário iniciar a edição, desaparecendo novamente depois que for tocada:

Kotlin

class ExampleFragment : Fragment() {
    ...
    fun updateToolbar() {
        isEditing = !isEditing

        val saveItem = viewBinding.myToolbar.menu.findItem(R.id.action_done)
        saveItem.isVisible = isEditing

    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    public void updateToolbar() {
        isEditing = !isEditing;

        MenuItem saveItem = viewBinding.myToolbar.getMenu().findItem(R.id.action_done);
        saveItem.setVisible(isEditing);
    }

}

Se estiver presente, o botão de navegação aparecerá no início da barra de ferramentas. Quando você define um ícone de navegação na barra de ferramentas, ela fica visível. Você também pode definir um onClickListener() específico de navegação, que será chamado sempre que o usuário clicar no botão de navegação, conforme mostrado no exemplo a seguir:

Kotlin

class ExampleFragment : Fragment() {
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        ...
        myToolbar.setNavigationIcon(R.drawable.ic_back)

        myToolbar.setNavigationOnClickListener { view ->
            // Navigate somewhere.
        }
    }
}

Java

public class ExampleFragment extends Fragment {
    ...
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        ...
        viewBinding.myToolbar.setNavigationIcon(R.drawable.ic_back);
        viewBinding.myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Navigate somewhere.
            }
        });
    }
}