Diseño Android: ActionBar con Toolbar

Última actualización : 17/08/2016

android

La ActionBar es la barra superior presente en la inmensa mayoría de aplicaciones y habitualmente suele mostrar el nombre de la pantalla visualizada, el icono de la aplicación (o el del menú de navegación) y las acciones disponibles.

action bar

La ActionBar forma parte del profundo rediseño acometido por Google para Android 3/4 y su adopción fue bastante rápida. Para poder utilizarla en Android 2 era necesario recurrir a implementaciones propias o de terceros como la popular ActionBarSherlock pero en 2013 se incluyó en librería de compatibilidad.

Con Lollipop llegó Material Design y un nuevo rediseño visual tan importante como el que supuso la llegada de Android 4. Una de las novedades ha sido la aparición de la Toolbar que pretende ser un reemplazo de la ActionBar más potente y flexible. Mientras que la ActionBar es un elemento del sistema que se muestra en una Activity si se hereda de un tema que la incluya, Toolbar es simplemente un widget que aporta grandes ventajas:

  • Puede ubicarse en cualquier lugar.
  • Se puede ubicar más de una en la misma pantalla.
  • Es un ViewGroup por lo que se pueden incluir dentro la Toolbar otros widgets.
  • Fácilmente adaptable al tamaño de pantalla.
  • Sigue proporcionado la funcionalidad de la ActionBar facilitando por tanto su adopción.

En este tutorial veremos las funcionalidades básicas de ActionBar utilizando como implementación la Toolbar. En futuros artículos y tips se seguirán explorando las funcionalidades de ActionBar/Toolbar:

Creación de la ActionBar con Toolbar

El widget Toolbar forma parte de Android 5 (API 21) pero ha sido incluido en la librería de compatibilidad para que pueda ser utilizado en cualquier versión de Android. En este artículo se utilizará la Toolbar proporcionada por la librería de compatibilidad y el proyecto de ejemplo requerirá como mínimo Android Gingerbread (API 10).

Los pasos para utilizar una Toolbar a modo de ActionBar son los siguientes:

  1. Incluir la última versión de la librería de compatibilidad en el proyecto (módulo AppCompat). En Android Studio\Gradle se hace en el fichero /app/build.gradle

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:23.2.1'
    }
    

    Para más información sobre la importación de librerías en Eclipse ADT y Android Studio, consultar este artículo.

  2. Utilizar como tema base de la aplicación uno que no incluya la ActionBar (Theme.AppCompat.NoActionBar, Theme.AppCompat.Light.NoActionBar). Para ello se define en el AndroidManifest.xml el tema propio de la aplicación
    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity ...
    

    y se crea ese tema en el fichero /app/src/main/res/values/styles.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="colorPrimary">@color/primary</item>
            <item name="colorPrimaryDark">@color/primaryDark</item>
            <item name="android:textColorPrimary">@color/textColorPrimary</item>
        </style>
    
    </resources>    
    
    
    
  3. Añadir la Toolbar a la pantalla. Puesto la Toolbar se utilizará como ActionBar hay que asegurar que se muestre siempre en la parte superior de la pantalla y que tenga el tamaño predeterminado por el sistema.

    Se aplicará el tema ThemeOverlay.AppCompat.Dark.ActionBar para hacer que los textos tengan color blanco, o bien ThemeOverlay.AppCompat.ActionBar para color negro. Este color se aplicará también para los iconos que se muestren en la Toolbar siempre que sean una transparencia alpha, siendo este el caso de los iconos proporcionados por el sistema para el menú overflow (“los tres puntos”) o el botón de volver (“la flecha”).

    Con el atributo elevation se establece la sombra de la Toolbar en la parte inferior aunque esta sólo se visualizará en dispositivos con Lollipop.

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:minHeight="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:elevation="@dimen/elevation"       
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            tools:ignore="UnusedAttribute"/>
    
    </LinearLayout>
    
  4. La Activity debe heredar de AppCompatActivity y establecer la toolbar que hemos definido como implementación de la ActionBar (setSupportActionBar). Por defecto la ActionBar mostrará como título el label definido en el AndroiManifest.xml para la Activity (o la aplicación si este no se define) pero se puede personalizar el título utilizando el método setTitle de tal modo que si el parámetro es nulo no se mostrará título alguno. También se puede definir un “subtítulo” con el método setSubtitle.
    package toolbar.android.danielme.com.toolbardemo;
    
    import android.os.Bundle;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.View;
    
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            //getSupportActionBar().setTitle(null);
    
        }
    
    }
    

El resultado en Lollipop es el siguiente:

simple android toolbar

Icono de aplicación y botón “subir”

Originalmente a la izquierda de la ActionBar se mostraba el icono de la aplicación y en el caso de que no estemos en la pantalla principal la pulsación de este icono permite al usuario subir un nivel en la jerarquía de pantallas (lo cual por cierto no siempre equivale a pulsar el botón atrás de Android). Para indicar que esta funcionalidad está habilitada se muestra junto al icono una flecha.

android actionbar icons

Sin embargo, en Material Design el icono de la aplicación no debe mostrarse según las guías de estilo y, en el caso del botón para subir un nivel, simplemente se visualiza una flecha cuyo icono ya está incluido en la librería de compatibilidad. Este icono se habilita en la definición de la Toolbar:

    <android.support.v7.widget.Toolbar
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/toolbar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:elevation="@dimen/elevation"
        app:navigationIcon="?attr/homeAsUpIndicator"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        tools:ignore="UnusedAttribute"/>

También se puede habilitar de forma programática:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Si se desea en la Activity se puede implementar el listener correspondiente para atender a su pulsación.

package toolbar.android.danielme.com.toolbardemo;

import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        //getSupportActionBar().setTitle(null);

        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, R.string.up, Toast.LENGTH_SHORT).show();
            }
        });

    }

}

simple android toolbar

Acciones

En la ActionBar se proporcionan al usuario las acciones que puede realizar desde cada pantalla concreta. Estas acciones se muestran como un icono, un texto, un icono con un texto o dentro de un menú desplegable.

Las acciones de una ActionBar se definen como un menú estándar de Android por lo que son análogos a los menús que en Android 2 se desplegaban en la parte inferior de pantalla al pulsar el botón físico del Menú. Vamos a añadir a la ActionBar del proyecto de ejemplo las siguientes acciones:

  • Un icono “añadir” que se deberá mostrar siempre.
  • Un icono de edición que se muestra sólo si hay espacio en la ActionBar.
  • Un menú desplegable con tres entradas: Settings, Help y About.

Seguimos los siguientes pasos:

  1. Definir el menú en el fichero /app/src/main/res/menu/main_activity_menu.xml. Cada acción será un elemento de tipo item.

    <?xml version="1.0" encoding="utf-8"?>
    <menu 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"
        tools:context=".MainActivity">
    
        <item
            android:id="@+id/action_add"
            android:icon="@mipmap/ic_action_new"
            android:title="@string/action_add"
            app:showAsAction="always" />
    
        <item
            android:id="@+id/action_edit"
            android:icon="@mipmap/ic_action_edit"
            android:title="@string/action_edit"
            app:showAsAction="ifRoom" />
        
    
        <!-- MENU -->
    
        <item
            android:id="@+id/action_settings"
            android:title="@string/action_settings"
            app:showAsAction="never" />
    
        <item
            android:id="@+id/action_help"
            android:title="@string/action_help"
            app:showAsAction="never" />
    
        <item
            android:id="@+id/action_about"
            android:title="@string/action_about"
            app:showAsAction="never" />
    </menu>
    
  2. En el atributo showAsAction indicar el comportamiento visual de cada acción:
    • always: muestra siempre el botón de la acción aunque no haya espacio. Si se quiere destacar una acción principal para la pantalla Material Design recomienda utilizar el elemento “Floating Action Button”.
    • ifRoom: si hay espacio se muestra el botón de la acción, en caso contrario se visualiza en el menú.
    • never: nunca muestra el botón de la acción en la barra por lo que se muestra siempre en el menú.
    • withText: muestra un texto con el título de la acción y si se indicó el icono muestran ambos. Esta opción se suele combinar con otras, por ejemplo ifRoom|withText muestra el texto junto al icono si ambos caben y en caso contrario muestra sólo el icono, si el icono tampoco cabe entones la acción se muestra en el menú.
    • collapseActionView: la acción muestra un layout personalizado, por ejemplo un EditText.
  3. Indicar el tema visual del menú desplegable en la definición de la Toolbar.
        <android.support.v7.widget.Toolbar
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:minHeight="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/Theme.AppCompat.Light"
            app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />
    
  4. Implementar en la Activity el método onCreateOptionsMenu para indicar el menú a utilizar.
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.main_activity_menu, menu);
            return super.onCreateOptionsMenu(menu);
        }
    
  5. Definir la acción a realizar para cada elemento del menú en el método onOptionsItemSelected.
       @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case R.id.action_add:
                    action(R.string.action_add);
                    return true;
                case R.id.action_edit:
                    action(R.string.action_edit);
                    return true;
                case R.id.action_settings:
                    action(R.string.action_settings);
                    return true;
                case R.id.action_help:
                    action(R.string.action_help);
                    return true;
                case R.id.action_about:
                    action(R.string.action_about);
                    return true;
                default:
                    return super.onOptionsItemSelected(item);
            }
        }
    
        private void action(int resid) {
            Toast.makeText(this, getText(resid), Toast.LENGTH_SHORT).show();
        }
    
    

Este es el resultado en una pantalla de gran resolución.

toolbar actionbutton 2

En una pantalla de menor resolución en la que no hay espacio para mostrar la acción de edición ésta se muestra en el menú.

toolbar actionbutton

Personalizar el menú desplegable (overflow)

Tal y como se aprecia en la anterior captura, el menú desplegable (overflow) cubre casi toda la ActionBar. Ese es el comportamiento definido por Material Design pero en versiones previas de Android el menú se mostraba debajo de la ActionBar. Si queremos recuperar este comportamiento tendremos que jugar con dos estilos propios de los menús de tipo popup:

  • overlapAnchor: boolean que indica si el menú debe cubrir el botón que lo muestra. Por omisión es true.
  • dropDownVerticalOffset: desplazamiento vertical del menú con respecto a la posición en que se muestra por omisión.

Con overlapAnchor = false el menú aparece debajo del botón pero ocupa una pequeña parte de la ActionBar tal y como puede verse en la siguiente captura

toolbar overflow menu

Por ello, si queremos que el menú se muestre justo debajo de la ActionBar debemos aplicar también dropDownVerticalOffset. Su valor lo he calculado probando por lo que no es fiable, y además depende de la orientación del dispositivo.

Para personalizar el menú desplegable con estas propiedades en la aplicación de ejemplo hay que realizar los siguientes cambios:

  1. En el layout eliminamos el atributo app:popupTheme de la Toolbar ya que este estilo lo vamos a aplicar directamente desde el tema de la aplicación.
  2. En /res/styles.xml, definimos el estilo anterior y, a su vez, su propiedad actionOverflowMenuStyle que será otro estilo definido en el mismo fichero. Este último estilo contiene las dos propiedades que nos interesa modificar.
    <?xml version="1.0" encoding="utf-8"?>
    <resources xmlns:tools="http://schemas.android.com/tools">
    
        <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="colorPrimary">@color/primary</item>
            <item name="colorPrimaryDark">@color/primaryDark</item>
            <item name="android:textColorPrimary">@color/textColorPrimary</item>
            <item name="popupTheme">@style/PopupTheme</item>
        </style>
    
        <style name="PopupTheme" parent="Theme.AppCompat.Light">
            <item name="actionOverflowMenuStyle">@style/OverflowMenu</item>
            <!--https://github.com/danielme-com/-Android-popup-menu- -Support-library/blob/master/res/values/styles.xml-->
        </style>
    
        <!-- displays the overflow menu below the toolbar-->
        <style name="OverflowMenu" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
            <item name="android:dropDownVerticalOffset">-4dp</item>
            <item name="overlapAnchor">false</item>
        </style>
    
    </resources>
    
  3. Lamentablemente la configuración de estas propiedades depende de la versión de Android y de la orientación del dispositivo por lo que tendremos que crear tres nuevos ficheros de estilo:
    • /res/values-v21/styles.xml: Api 21+ (Lollipop) en orientación vertical

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <style name="OverflowMenu" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
              <item name="android:overlapAnchor">false</item>
              <item name="android:dropDownVerticalOffset">4dp</item>
          </style>
      </resources>
      
    • /res/values-land-v21/styles.xml: Api 21+ en horizontal
      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <style name="OverflowMenu" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
              <item name="android:overlapAnchor">false</item>
              <item name="android:dropDownVerticalOffset">8dp</item>
          </style>
      </resources>
      
    • /res/values-land/styles.xml: Versiones inferiores a Api 21 en horizontal
      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <style name="OverflowMenu" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
              <item name="android:dropDownVerticalOffset">1dp</item>
              <item name="overlapAnchor">false</item>
          </style>
      </resources>
      

Tras la aplicación de estos cambios obtendremos el siguiente resultado:

toolbar overflow menu

Con respecto al resto de propiedades de estilo del menú overflow, se aplican tal y como se muestran en el tutorial Diseño Android:Popup Menu.

Pestañas

Ver el tutorial Diseño Android: Toolbar y Pestañas con Material Design.

Código de ejemplo

El proyecto completo se encuentra disponible en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

10 Responses to Diseño Android: ActionBar con Toolbar

  1. Sixto dice:

    Muy buen tutorial, felicitaciones. Me gustaría saber si hay una forma de alinear el menú overflow con la parte inferior del toolbar?

    Gracias de antemano…

  2. Sixto dice:

    Gracias, me ha servido de mucha ayuda este tutorial.

  3. Omar Bautista dice:

    excelente, gracias por el aporte

  4. Laura dice:

    Es genial, sabrias decirme como hacer el efecto con las pestañas como en el actionbar swipe

    • danielme.com dice:

      Se puede conseguir una toolbar con pestañas con estilo Material Design usando un layout con la siguiente estructura y basado en los widgets de las support library:

      <android.support.design.widget.AppBarLayout >

      <android.support.v7.widget.Toolbar/>

      <android.support.design.widget.TabLayout/>

      </android.support.design.widget.AppBarLayout>

      <android.support.v4.view.ViewPager/>

      Puedes ver una implementación de ejemplo en https://github.com/chrisbanes/cheesesquare

  5. Rodrigo dice:

    Hola … quiero hacer una app que haga uso de botones y de un toolbar, creo el layout, pero en el .java quiero hacer uso de la opciones del ToggleButton y si extendiendo AppCompatActivity me bloquea el código relacionado al ToggleButton y si extiendo Activity me bloquea lo relacionado al actionBar…

  6. Wandy dice:

    Excelente amigo, muchas gracias por tu ayuda!!!

  7. Joaquín dice:

    He estado viendo tutoriales sobre este tema y este es el más claro hasta ahora, pero por desgracia, cumpliendo al pie de la letra con el código que ha subido a GitHub, no me sale el desplazamiento del menú desplegable. Es como si overlapAnchor estuviera en true en el Theme y tampoco funcionara el desplazamiento vertical dropDownVerticalOffset. Le he estado dando vueltas y no se me ocurre nada. Si me pudieras orientar porqué te lo agradecería mucho.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: