La barra de la app superior proporciona un lugar coherente en la parte superior de la ventana de la app para mostrar información y acciones desde la pantalla actual.
La propiedad de la barra de la app varía según las necesidades de tu app. Cuando usas fragmentos, la barra de la app se puede implementar como una ActionBar
que pertenece a la actividad del host o a una barra de herramientas dentro del diseño de tu fragmento.
Si todas tus pantallas usan la misma barra de la app que siempre está en la parte superior y abarca el ancho de la pantalla, usa una barra de acciones proporcionada por el tema y alojada por la actividad. El uso de barras de la app temáticas ayuda a mantener una apariencia coherente y brinda un lugar para alojar menús de opciones y un botón Arriba.
Usa una barra de herramientas alojada por el fragmento si deseas tener más control sobre el tamaño, la ubicación y la animación de la barra de la app en varias pantallas. Por ejemplo, quizás necesites una barra de la app que se contraiga o que solo use la mitad del ancho de la pantalla y que esté centrada verticalmente.
En diferentes situaciones, se requieren enfoques distintos para cuestiones como aumentar menús y responder a la interacción del usuario. Comprender los diferentes enfoques y usar el mejor para tu app te ahorra tiempo y ayuda a garantizar que tu app funcione correctamente.
Los ejemplos de este tema hacen referencia a un ExampleFragment
que contiene un perfil editable. El fragmento aumenta el siguiente menú definido por XML en la barra de la app:
<!-- 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>
El menú contiene dos opciones: una para navegar a una pantalla del perfil y otra para guardar los cambios de perfil que se realicen.
Barra de la app perteneciente a una actividad
La barra de la app suele ser propiedad de la actividad del host. Cuando esto ocurre, los fragmentos pueden interactuar con la barra de la app anulando los métodos del framework que son llamados durante la creación del fragmento.
Cómo registrarse con la actividad
Debes informar al sistema que el fragmento de la barra de la app participa en la propagación del menú de opciones. Para ello, llama a setHasOptionsMenu(true)
en el método onCreate(Bundle)
de tu fragmento, como se muestra en el siguiente ejemplo:
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)
le indica al sistema que tu fragmento desea recibir devoluciones de llamada relacionadas con el menú. Cuando ocurre un evento relacionado con el menú, como un clic, primero se llama al método de control de eventos en la actividad antes de que se lo llame en el fragmento.
Sin embargo, no te bases en este orden en la lógica de tu aplicación. Si la misma actividad aloja varios fragmentos, cada uno puede proporcionar opciones de menú, en cuyo caso el orden de devolución de llamada depende del orden en el que se agregan los fragmentos.
Cómo aumentar el menú
Para combinar tu menú con el menú de opciones de la barra de la app, anula onCreateOptionsMenu()
en tu fragmento. Ese método recibe el menú actual de la barra de la app y un MenuInflater
como parámetros. Usa el amplificador de menú a fin de crear una instancia del menú del fragmento y, luego, combinarla con el menú actual, como se muestra en el siguiente ejemplo:
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); } }
En la Figura 2, se muestra el menú actualizado.
Cómo controlar eventos de clic
Cada actividad y fragmento que participa en el menú de opciones puede responder a toques. El elemento onOptionsItemSelected()
del fragmento recibe el elemento de menú seleccionado como un parámetro y muestra un valor booleano para indicar si se consume el toque. Una vez que una actividad o un fragmento muestre true
desde onOptionsItemSelected()
, ningún otro fragmento participante recibirá la devolución de llamada.
En tu implementación de onOptionsItemSelected()
, usa una declaración switch
en el itemId
del elemento de menú. Si el elemento seleccionado es tuyo, controla el toque de forma adecuada y muestra true
para indicar que se gestionó el evento de clic. Si el elemento seleccionado no es tuyo, llama a la implementación de super
. De forma predeterminada, la implementación de super
muestra false
para permitir que continúe el procesamiento del menú.
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); } } }
Cómo modificar el menú de forma dinámica
Coloca la lógica para ocultar o mostrar un botón o cambiar el ícono en onPrepareOptionsMenu()
.
Se llama a este método justo antes de que se muestre el menú.
Siguiendo con el ejemplo anterior, el botón Guardar debe ser invisible hasta que el usuario comience a editar y debería desaparecer después de que el usuario efectúe la operación de guardar. Si agregas esta lógica a onPrepareOptionsMenu()
, el menú se presenta de forma correcta:
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); } }
Cuando necesites actualizar el menú, como cuando un usuario presiona el botón Editar para editar la información del perfil, llama a invalidateOptionsMenu()
en la actividad del host para solicitar que el sistema llame a onCreateOptionsMenu()
.
Luego de realizar la invalidación, puedes hacer las actualizaciones en onCreateOptionsMenu()
. Una vez que el menú aumente, el sistema llamará a onPrepareOptionsMenu()
y lo actualizará a los efectos de reflejar el estado actual del 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 la app perteneciente a un fragmento
Si la mayoría de las pantallas de tu app no necesita una barra, o bien si una necesita una diferente, puedes agregar una Toolbar
a tu diseño del fragmento. Si bien puedes agregar una Toolbar
en cualquier lugar de la jerarquía de vistas del fragmento, en general, debes mantenerla en la parte superior de la pantalla. Para usar la Toolbar
en el fragmento, proporciona un ID y obtén una referencia a ella en tu fragmento, como lo harías con cualquier otra vista. También puedes animar la barra de herramientas con comportamientos CoordinatorLayout
.
<androidx.appcompat.widget.Toolbar
android:id="@+id/myToolbar"
... />
Cuando usas una barra de la app perteneciente a un fragmento, Google recomienda que uses directamente las APIs de Toolbar
. No uses setSupportActionBar()
ni las APIs de menú de Fragment
, que son adecuadas solo para las barras de la app pertenecientes a una actividad.
Cómo aumentar el menú
El método de conveniencia inflateMenu(int)
de Toolbar
toma el ID de un recurso de menú como parámetro. Para aumentar un recurso de menú XML en tu barra de herramientas, pasa el resId
a este método, como se muestra en el siguiente ejemplo:
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 aumentar otro recurso de menú XML, llama de nuevo al método con el resId
del menú nuevo. Los nuevos elementos de menú se agregan a este y los elementos de menú existentes no se modifican ni se quitan.
Si deseas reemplazar el conjunto de menús existente, borra el menú antes de llamar a inflateMenu(int)
con el ID del menú nuevo, como se muestra en el siguiente ejemplo:
Kotlin
class ExampleFragment : Fragment() { ... fun clearToolbarMenu() { viewBinding.myToolbar.menu.clear() } }
Java
public class ExampleFragment extends Fragment { ... public void clearToolbarMenu() { viewBinding.myToolbar.getMenu().clear() } }
Cómo controlar eventos de clic
Puedes pasar un OnMenuItemClickListener
directamente a la barra de herramientas mediante el método setOnMenuItemClickListener()
. Este objeto de escucha se invoca cuando el usuario selecciona un elemento de menú de los botones de acción que se presentan al final de la barra de herramientas o del menú ampliado asociado. El MenuItem
seleccionado se pasa al método onMenuItemClick()
del objeto de escucha y se puede usar para consumir la acción, como se muestra en el siguiente ejemplo:
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; } }); } }
Cómo modificar el menú de forma dinámica
Cuando la barra de la app es propiedad de tu fragmento, puedes modificar la Toolbar
en el tiempo de ejecución de la misma manera que lo harías para cualquier otra vista.
Siguiendo con el ejemplo anterior, la opción Guardar del menú debe ser invisible hasta que el usuario comience a editar y debería desaparecer nuevamente cuando se la presione:
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); } }
Cómo agregar un ícono de navegación
Si está presente, el botón de navegación aparecerá al comienzo de la barra de herramientas.
Este botón será visible si estableces un ícono de navegación en la barra de herramientas. También puedes configurar un onClickListener()
específico de la navegación, al que se llama cada vez que el usuario hace clic en el botón de navegación, como se muestra en el siguiente ejemplo:
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. } }); } }