ActionBar y Tabs en Android

Podríamos decir que la ActionBar es una barra de herramientas que nos permite ubicar al usuario en todo momento indicando en que actividad se encuentra (a través de un titulo y subtitulo) y a parte nos proporciona un espacio para crear acciones de usuario (ya sean botones de acción, botón de búsqueda, listas desplegables, tabs, ...)

La API de esta herramienta apareció por primera vez en Android 3.0 (API 11) pero a través de la librería de compatibilidad "android-support-v7-appcompact" podemos hacerla compatible a partir de Android 2.1 (API 7). En esta guia haremos uso de dicha librería para hacer compatible la ActionBar con el mayor numero de dispositivos posibles.

Para la realización de este articulo se ha cogido como base la guia de desarrolladores Android: ActionBar. Al final de este articulo tendremos la descarga del proyecto con todo lo incluido en él.

Comentar que tendríamos la posibilidad de crear una ActionBar a través de una librería externa que prácticamente es una extensión de la librería de compatibilidad que usaremos en este articulo. Dicha librería se llama ActionBarSherlock y es compatible a partir de Android 2.0 (API 5).


Tabla de contenidos
 
     1. Añadir librería de compatibilidad
   
     2. Utilizar ActionBar en nuestro proyecto
            2.3 Habilitar el botón volver en la ActionBar
            2.4 Dividir ActionBar
            2.5 Añadir drop-dwon (spinner)
            2.6 Añadir una vista de acción
            2.7 Añadir un proveedor de acción
            2.8 Crear layout personalizado

     3. Crear menú de navegación (Navigation Drawer)

     4. Creación de pestañas (Tabs)
            4.1 Crear views deslizantes (ViewPager)
            4.2 Crear tabs para ViewPager
            4.3 Utilizar view desplazables

     5. Aplicar estilo a la ActionBar

     6. Código fuente del articulo




1. Añadir librería de compatibilidad

Primero debemos importar la librería a nuestro workspace siguiendo estos pasos:
  1. File/Import/Android/Existing Android Code Into Workspace.
  2. Buscamos la librería ubicada en la carpeta /android-sdk/extras/android/support/v7/appcompact/
  3. Seleccionamos la librería y finalizamos.
Con esto ya tenemos la librería cargada en nuestro workspace. Lo siguiente es añadir la librería a nuestro proyecto siguiendo estos pasos:
  1. Seleccionamos nuestro proyecto y entramos en sus Propiedades (hay varias maneras de hacerlo: desde el menú Project, con click derecho encima de nuestro proyecto o combinando las teclas Alt+Enter).
  2. Una vez abierta la nueva ventana pinchamos abajo del todo en Add...
  3. Seleccionamos la librería y aceptamos.
Al final debe quedar algo muy similar a esta captura:




2. Utilizar ActionBar en nuestro proyecto

Para hacer visible la ActionBar en nuestra aplicación simplemente deberemos editar el AndroidManifest y establecer un theme del conjunto de temas "Theme.AppCompact". Podemos hacerlo directamente en <application ...> o en la <activity ...>, todo dependerán de nuestras necesidades.
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
    </application>
    <activity
        ...
        ...
        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
    </activity>

Seguidamente en nuestra actividad tendremos que extender la clase "ActionBarActivity" y con esto ya podríamos ejecutar la aplicación y tendríamos visible la ActionBar en pantalla. Por defecto pondrá como icono el establecido en "android:icon" y como titulo lo establecido en "android:label".

Para poder trabajar con ella tendremos que crear una instancia del objeto ActionBar.
    ActionBar actionBar = getSupportActionBar();

Y ya podríamos usar métodos como los siguientes:
    actionBar.hide();                        //Ocultar ActionBar
    actionBar.setIcon(Drawable);             //Establecer icono
    actionBar.setTitle(CharSequence);        //Establecer titulo
    actionBar.setSubtitle(CharSequence);     //Establecer Subtitulo



2.1 Añadir elementos de acción

Para crear elementos de acción primero tenemos que crear un recurso del tipo "menu" en el que indicaremos todos los items o elementos de acción que nos sean necesarios. Este recuso hay que crearlo dentro de la carpeta /res/menu/

A continuación vemos un ejemplo que explicaremos seguidamente:
<menu 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:yourapp="http://schemas.android.com/apk/res-auto">

    <item 
        android:id="@+id/buscar" android:title="@string/menu_buscar"
        android:icon="@drawable/buscar" yourapp:showAsAction="ifRoom|withText"/>
    <item 
        android:id="@+id/cortar" android:title="@string/menu_cortar"
        android:icon="@drawable/cortar" yourapp:showAsAction="ifRoom|withText"/>
    <item 
        android:id="@+id/copiar" android:title="@string/menu_copiar"
        android:icon="@drawable/copiar" yourapp:showAsAction="ifRoom|withText"/>
    <item 
        android:id="@+id/eliminar" android:title="@string/menu_eliminar"
        android:icon="@drawable/eliminar" yourapp:showAsAction="ifRoom|withText"/>
    <item 
        android:id="@+id/compartir" android:title="@string/menu_compartir"
        android:icon="@drawable/compartir" yourapp:showAsAction="ifRoom|withText"/>

</menu>

Para crear un ítem o elemento de acción simplemente utilizaremos los atributos "id" y "title". Con esto conseguiremos que en nuestra aplicación nos muestre un menú desplegable.

Si lo que queremos es mostrar los elementos de acción como un icono en el ActionBar, deberemos añadir a la declaración de nuestro menú, la siguiente herramienta:
    xmlns:yourapp="http://schemas.android.com/apk/res-auto"
Donde "yourapp" tenemos que sustituirlo por el nombre del paquete de nuestra aplicación, ejemplo:
    xmlns:com.example.actionbar="http://schemas.android.com/apk/res-auto"
Una vez hecho esto ya podremos hacer uso del atributo "showasaction" en el que tendremos que hacer exactamente lo mismo con "yourapp". Este atributo nos permite controlar de que manera se va a mostrar el elemento de acción. Tiene las siguientes configuraciones:
  1. ifRoom (Mostrara el "icon" en el ActionBar si tiene espacio)
  2. always (Mostrara siempre el "icon" en el ActionBar)
  3. withText (Se debe usar junto a "ifRoom" o "always" y mostrara el "icon" + "title" si tiene espacio)
  4. never (El ítem siempre estará incluido en el menú desplegable)
Deberemos tener en cuenta que hacer uso de la conflagración "always" puede causar problemas de diseño en dispositivos con pantallas pequeñas, por lo que es mas que recomendable utilizar la configuración "ifRoom" para que nos gestione el espacio disponible y muestre automáticamente los elementos de acción que entren en ese espacio.

Una vez creado el recurso menú con los elementos de acción necesarios deberemos inflar la vista en nuestra activity a través del siguiente método:
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

Para la creación de los iconos podemos visitar esta herramienta de Android Studio: Action Bar and Tab Icon Generator

El resultado puede ser el siguiente:




2.2 Manejar clicks en los elementos de acción

Cuando pulsamos un elemento de acción, el sistema hace una llamada al método "onOptionsItemSelected()". A través de este método podremos identificar que botón de acción se a pulsado, simplemente le tendremos que aplicar el método "getItemId()" a su parámetro "MenuItem" y como resultado tendremos id del ítem pulsado. Podemos ver todo esto en un ejemplo:
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.buscar:
        Toast.makeText(getApplicationContext(), "BUSCAR", Toast.LENGTH_SHORT).show();
        return true;
    case R.id.cortar:
        Toast.makeText(getApplicationContext(), "CORTAR", Toast.LENGTH_SHORT).show();
        return true;
    case R.id.copiar:
        Toast.makeText(getApplicationContext(), "COPIAR", Toast.LENGTH_SHORT).show();
        return true;
    ...
    ...
    ...
    default:
        return super.onOptionsItemSelected(item);
    }
}
Lo primero que hacemos es crear un switch para manejar los diferentes botones de acción que hayamos declarado en nuestro recurso menú. Al switch le aplicamos el método "getItemId()" para conocer la id del botón de acción que ha sido pulsado y para terminar creamos tantos casos como botones de acción tengamos. En este caso simplemente mostramos un Toast al pulsar un botón de acción.



2.3 Habilitar el botón volver en la ActionBar


Android nos permite habilitar el icono de la ActionBar como un botón volver. Para ello tenemos que seguir dos pasos:

  1. Activar el botón volver en la ActionBar a través del siguiente método:
    actionBar.setDisplayHomeAsUpEnabled(true);

  1. Indicar a que actividad volverá después de pulsar el botón volver, para ello tenemos dos posibilidades de hacerlo:
(2.1) Especificar la actividad padre en el AndroidManifest (es la mejor opción cuando la actividad padre siempre es la misma, a continuación se muestra un ejemplo)
    <activity
        android:name="com.example.actionBar.ActionBarActivity"
        android:parentActivityName="com.example.actionBar.MenuPrincipal"> 
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.actionBar.MenuPrincipal"/>        
    </activity>
(2.2) Reemplazar los metodos "getSupportParentActivityIntent()" y "onCreateSupportNavigateUpTaskStack()" en nuestra activity (esta forma es apropiada cuando la actividad padre puede ser diferente).


2.4 Dividir ActionBar

Android nos ofrece la posibilidad de dividir la ActionBar (Split ActionBar), esto quiere decir que nuestra aplicación podrá tener un panel superior (ActionBar) y un panel inferior (con los elementos de acción). Para hacer uso de una ActionBar dividida simplemente deberemos establecer un atributo para cada activity que lo necesite dentro del AndroidManifest.
  1. Añadiendo el atributo "uiOptions" a cada activity conseguiremos una ActionBar dividida (este método solo es compatible con versiones superiores a un nivel de API 14)
  2. Para hacerlo compatible con versiones anteriores de Android tendremos que agregar un <meta-data>  a cada activity
Un ejemplo para hacerlo compatible con la mayoría de versiones seria el siguiente:
    <activity
        android:name="com.example.actionbar.DividirActionBar"
        android:uiOptions="splitActionBarWhenNarrow">
        <meta-data 
            android:name="android.support.UI_OPTIONS"
            android:value="splitActionBarWhenNarrow" />
    </activity>

El resultado puede ser el siguiente:



2.5 Añadir un drop-down (spinner)

Podremos crear una lista deplegable como la que muestra la imagen:


Empezaremos creando un recurso string-array que nos servira para almacenar los items de la lista desplegable, podemos hacerlo tanto dentro del archivo strings.xml o bien podemos crear uno nuevo, como nos sea mas cómodo.
    <resources>
        <string-array name="lista">
            <item>Lunes</item>
            <item>Martes</item>
            <item>Miercoles</item>
            <item>Jueves</item>
            <item>Viernes</item>
            <item>Sabado</item>
            <item>Domingo</item>
        </string-array>
    </resources>

El siguiente paso seria modificar el modo de navegación de la ActionBar y establecerlo en lista deplegable. Para ello utilizaremos el siguiente código en el onCreate de nuestra activity:
    ActionBar actionBar = getSupportActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

Una vez hecho esto necesitaremos crear un adaptador "SpinnerAdapter" que utilizaremos para indicar que items se mostraran en la lista desplegable (el recurso string-array creado antes) y que diseño tendrá dicha lista.
    SpinnerAdapter adapter = ArrayAdapter.createFromResource(this, 
                R.array.lista, android.R.layout.simple_spinner_dropdown_item);

Para terminar implementamos la interface "ActionBar.OnNavigationListener" que nos servirá para manejar los eventos del usuario al pulsar un ítem de la lista desplegable. Vamos a dividir este paso en tres:
  1. Implementar interface "ActionBar.OnNavigationListener"
  2. Aplicar interface a nuestro objeto ActionBar a traves del metodo "setListNavigationCallbacks()"
  3. Sobreescribir el método obligado de esta interface "onNavigationItemSelected()"
    // Implementar interface
    ... implements ActionBar.OnNavigationListener { ...}
    // Aplicar interface a nuestro ActionBar (dentro del onCreate)
    actionBar.setListNavigationCallbacks(adapter, this); 
    // Sobreescribir metodo
    public boolean onNavigationItemSelected(int arg0, long arg1) {
        switch (arg0) {
            case 0:
                // Opcion seleccionada Lunes
                break;
            case 1:
                // Opcion seleccionada Martes
                break;
            ...
            ...
        }
        return false;
    }



2.6 Añadir una vista de acción

Una vista de acción es simplemente un widget que aparece en nuestro ActionBar como un elemento de acción. Cada vez que pulsemos ese elemento de acción nuestro ActionBar se transformara ofreciendo un acceso rápido a otras opciones sin tener que cambiar de activity, fragment o ActionBar. Uno de los mas conocidos es la barra de búsqueda que aparece en unas cuantas aplicaciones, al pulsar sobre el icono de la lupa se nos abre automáticamente un edittext:



Lo primero que tenemos que hacer para crear una vista de acción es generar un recurso "menu" indicando el atributo "actionLayout" o "actionViewClass". De esta manera crearemos un recurso de diseño o una clase widget respectivamente. Vamos a ver como crear el recurso para el "SearchView" de la imagen de arriba:
<menu 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:com.example.actionbar="http://schemas.android.com/apk/res-auto" >
    
    <item
        android:id="@+id/buscar"
        android:title="@string/menu_buscar"
        android:icon="@drawable/ic_action_search"
        com.example.actionbar:showAsAction="ifRoom|collapseActionView"
        com.example.actionbar:actionViewClass="android.support.v7.widget.SearchView"/>
    
</menu>
Cosas a tener en cuenta, primero acordaros de cambiar el nombre de paquete y poner el de vuestra aplicación (sustituir "com.example.actionbar").
En el atributo showAsAction estamos indicando "collapseActionView" para establecer que el ítem tiene que aparecer en la aplicación como un elemento de acción (imagen 1).
Y por ultimo en el atributo actionViewClass establecemos la clase widget del SearchView a través de la librería de soporte v7.

Solo nos quedaría configurar el método onCreateOptionsMenu para hacer funcional esta vista de acción. Voy a explicar como hacerlo y a parte le vamos a aplicar dos listeners. Uno para cuando se expanda y se cierre el elemento de acción y otro para cuando el usuario introduzca un texto y lo acepte. Por lo tanto pongo el código y luego lo explico un poco:
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.vistabusqueda, menu);
     
    MenuItem searchItem = menu.findItem(R.id.buscar);
    
    SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
  
    // LISTENER PARA EL EDIT TEXT   
    searchView.setOnQueryTextListener(this);
    // LISTENER PARA LA APERTURA Y CIERRE DEL WIDGET
    MenuItemCompat.setOnActionExpandListener(searchItem, this);
     
    return super.onCreateOptionsMenu(menu);
}
Lo primero que hacemos es inflar la vista creada anteriormente a través del método getMenuInflater().
Seguidamente creamos un objeto MenuItem  correspondiente al ítem creado en el recurso menú. Este sera el elemento de acción que veremos en el ActionBar.
Seguimos creando otro objeto SearchView al que le aplicaremos la vista del elemento de accion que hemos creado antes, para ello utilizamos el método getActionView(). De esta manera estamos convirtiendo el elemento de acción en una vista de acción. Si ejecutamos el código en este punto obtendremos como resultado lo que se ve en las imágenes de arriba.

Para configurar los listener debemos implementar las interfaces "OnQueryTextListener" y "OnActionExpandListener". Una vez hecho esto ya podemos aplicar los listeners a los dos objetos creados en el "onCreateOptionsMenu" (las dos siguientes lineas de código).

Al implementas estas dos interfaces estamos obligados a sobreescribir los siguientes métodos:
public boolean onQueryTextChange(String arg0) {
    return false;
}
public boolean onQueryTextSubmit(String arg0) {
    return false;
}
public boolean onMenuItemActionCollapse(MenuItem arg0) {
    return true;
}
public boolean onMenuItemActionExpand(MenuItem arg0) {
    return true;
}
Los dos primeros métodos corresponden a la interface "OnQueryTextListener". Con el primero podemos trabajar en el momento que el usuario pincha el elemento de acción y se expande el edittext capturando todo lo que haga. Con el segundo método podremos trabajar cuando el usuario acepte una búsqueda.

Y para terminar los dos siguientes métodos corresponden a la interface "OnActionExpandListener". El primero lo usaremos para cuando el elemento de acción se cierre. Y el segundo método para cuando el elemento de acción se expanda.



2.7 Añadir un proveedor de acción

Es muy similar al ejemplo anterior (vista de acción) pero en este caso un "action provider" o proveedor de acción reemplazara a un elemento de acción con un diseño personalizado. Esto quiere decir que un proveedor de acción tiene todo el control del elemento de acción y es capaz de mostrar un submenu al pulsar el botón de acción entre otras cosas.

Tenemos la posibilidad de crear nuestro propio proveedor de acción utilizando la clase "ActionProvider" aunque Android por defecto nos ofrece la posibilidad de crear alguno como el "ShareActionProvider" que seria el botón de compartir que aparece en alguna que otra aplicacióon, el de la imagen:


En este caso tenia preparado crear lo que se ve en la imagen que es lo que incluye el código fuente del final del articulo pero he decidido crear un ActionProvider personalizado y hacer algo similar al ejemplo anterior (vista de acción) para ver el resultado mas rápidamente y tener una base de esto.

La documentación Android nos dice que tenemos que crear nosotros mismos nuestro ActionProvider, por lo tanto empezaremos creando una clase que extienda de ActionProvider:
public class BusquedaAP extends ActionProvider{
 
    Context context;

    public BusquedaAP(Context context) {
        super(context);
        this.context = context;
    }

    public View onCreateActionView() {
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        View view = layoutInflater.inflate(R.layout.ap_busqueda, null);
        return view;
    }
}

Después necesitaremos crear el layout que estamos inflando en el método "onCreateActionView":
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
    
    <EditText
        android:id="@+id/edit"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="text"/>

</RelativeLayout>

Continuamos creando un recurso menú que hará referencia a nuestra clase "BusquedaAP" a través del atributo actionProviderClass:
<menu 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:com.example.actionbar="http://schemas.android.com/apk/res-auto">

    <item
       android:id="@+id/buscar"
       android:title="@string/menu_buscar"
       android:icon="@drawable/ic_action_search"
       com.com.example.actionbar:showAsAction="always|collapseActionView"
       com.com.example.actionbar:actionProviderClass="com.example.actionbar.BusquedaAP"/>
    
</menu>
Recordar cambiar el nombre del paquete y la clase en el atributo "actionProviderClass" para hacer referencia a la clase que hayamos extendido de ActionProvider.

Por ultimo solo nos queda configurar el código Android, para ello inflaremos el menú que acabamos de crear en el método "onCreateOptionsMenu()":
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.busqueda_ap, menu);
        return super.onCreateOptionsMenu(menu);
    }

El resultado sera el siguiente:



Es un ejemplo muy rápido de las posibilidades que ofrece utilizar un proveedor de acción o ActionProvider. El tema es un poco mas extenso al utilizar la clase ActionProvider porlo que es mas que recomendable echarle un ojo en google. Pero la idea es esa, adaptar un botón de acción a lo que nosotros queramos.



2.8 Crear layout personalizado

Otra opción que nos ofrece Android es la posibilidad de aplicar un layout personalizado a la ActionBar, de esta manera se nos abre otro abanico de posibilidades.

El primer paso seria crear un layout con la disposición que necesitemos de la ActionBar.

Una vez creado el layout nos vamos a nuestra activity y simplemente tendríamos que poner el modo de navegación de la ActionBar en custom y aplicarle el nuevo layout, metiendo el siguiente código en el onCreate podríamos realizarlo:
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
    actionBar.setCustomView(R.layout.actionbar_top);
A parte de introducir este código en el onCreate tendriamos que configurar los botones, textos, imagenes que hayamos metido en el layout personalizado.

Pero el resultado puede ser algo similar a esto:




3. Crear menú de navegación


Este tipo de menú se llama "Navigation Drawer" y es un panel oculto que esta ubicado en el borde izquierdo de la pantalla. Se puede hacer visible de dos maneras, o bien haciendo un gesto desde la izquierda de la pantalla o pulsando directamente el icono de la ActionBar.

Para añadir el menú de navegación a nuestra aplicación tenemos que hacer uso de la API "DrawerLayout" disponible en la librería de compatibilidad v4.

Primero deberemos crear el layout del DrawerLayout:
    <android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <ListView 
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:choiceMode="singleChoice"
            android:background="#111"/>
    </android.support.v4.widget.DrawerLayout>
Al hacer uso de DrawerLayout, deberemos especificar 2 tipos de vista:

  1. Una vista principal que sera la mostrada por la activity (en este caso es un FrameLayout)
  2. Otra vista para el menú de navegación (en este caso un simple listview) 

En la segunda vista (listview) deberemos indicar su gravedad (normalmente "start") y su anchura (no debe sobrepasar los 320dp).

Una vez creada la vista del Navigation Drawer ya podemos pasar a nuestra actividad para trabajar con ella. Primero extenderemos la clase "ActionBarActivity" y con el siguiente código crearíamos nuestra actividad con su Navigation Drawer:
public class CrearCajon extends ActionBarActivity {

    private DrawerLayout cajon;
 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.cajon);

        String[] valores = getResources().getStringArray(R.array.cajon);
        cajon = (DrawerLayout) findViewById(R.id.drawer_layout);
        ListView opciones = (ListView) findViewById(R.id.left_drawer);
        opciones.setAdapter(new ArrayAdapter(this, R.layout.plantilla_cajon, valores));
    }
}
Primero establecemos la vista creada anteriormente a través del método setContentView().
Creamos un array String que usaremos para aplicar al ListView (serán todas las opciones de nuestro Navigation Drawer)
Continuamos creando un objeto ListView.
Y aplicamos un adaptador para ese ListView

Con esto ya podríamos visualizar la actividad con su menú de navegación. Lo único que para acceder al menú solo podríamos hacerlo dibujando el gesto desde el lado izquierdo. Vamos a continuar y a ver como podríamos habilitar el icono de la aplicación para acceder a este menú.



3.1 Habilitar el icono de la ActionBar

Lo primero que tenemos que hacer es crear un objeto de la clase "ActionBarDrawerToggle" y habilitar el icono de la aplicación como botón. Por lo tanto empezaremos añadiendo el siguiente código al OnCreate anterior:
    // CREAMOS EL OBJETO FUERA DEL ONCREATE
    private ActionBarDrawerToggle toggle;

    // ESTO DENTRO DEL ONCREATE
    toggle = new ActionBarDrawerToggle(this, cajon, R.drawable.ic_drawer, 
                                       R.string.drawer_open, R.string.drawer_close);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);
El constructor del objeto "toggle" nos pide como parámetros la actividad que aloja el menú de navegacion (this), el DrawerLayout (cajon), un icono drawable y dos palabras que describirán la apertura y cierre del cajón (para la accesibilidad).

Para terminar de habilitar el icono de la aplicación deberemos sobreescribir los siguientes métodos en nuestra activity:
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        toggle.syncState();
    }
    
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        toggle.onConfigurationChanged(newConfig);
    }
    
    public boolean onOptionsItemSelected(MenuItem item) {
        if (toggle.onOptionsItemSelected(item)) {
          return true;
        }
        return super.onOptionsItemSelected(item);
    }
El primero método sera llamado una vez que la actividad haya sido creada (justo después del onStart y onRestoreInstanceState). En el simplemente le aplicamos el método "syncState()" al objeto "toggle" para sincronizar el estado del icono de la aplicación con nuestro DrawerLayout.

El segundo método sera llamado cuando haya cambios en la configuración del sistema. Por lo tanto aplicaremos la nueva configuración a nuestro objeto "toggle" a través del método "onConfigurationChanged()".

Y el ultimo método no es realmente necesario pero nos puede servir para manejar los clicks en nuestro menú de navegación. Este sera llamado cuando tenga lugar un click en nuestro menú. En el simplemente indicamos que si se a pulsado una opción del menú devuelva true. Tendríamos la posibilidad de manejar los clicks en nuestro menú a través del parámetro MenuItem de dicho método.


El resultado después de crear todo lo anterior es el siguiente:




3.2 Manejar eventos click del menú

Podríamos hacerlo de dos maneras o bien utilizando el método anterior (onOptionsItemSelected) o implementando la interface "ListView.OnItemClickListener". En este caso usaremos la segunda opción.

Empezamos implementando la interface y se la aplicamos a nuestro listview añadiendo esto al código que vamos creando en nuestra actividad:
    opciones.setOnItemClickListener(this);
Esta interface que estamos implementando nos obliga a sobreescribir el método "onItemClick()":
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
    switch (arg2) {
    case 0:
        Toast.makeText(getApplicationContext(), "BUSCAR", Toast.LENGTH_SHORT).show();
        break;
    case 1:
        Toast.makeText(getApplicationContext(), "CORTAR", Toast.LENGTH_SHORT).show();
        break;
    ...
    ...
    ...
    }
    cajon.closeDrawer(opciones);
}
Para conocer la posición del ítem que se a pulsado del menú utilizaremos el parámetro "arg2" y creamos un switch para manejar todas las opciones de nuestro menú de navegación. Deberemos acordarnos de cerrar el menú de navegación con el método "closeDrawer()" indicando la vista a cerrar, en nuestro caso es el listview.



3.3 Manejar eventos de apertura y cierre del menú

Android también nos ofrece la posibilidad de manejar estos eventos y controlar en cada momento que hacer cuando se abre o se cierra el menú de negación.

En este caso vamos a implementar la interface "DrawerListener" y se la aplicamos a nuestro objeto DrawerLayout:
    cajon.setDrawerListener(this);
Esta interface que estamos implementando nos obliga a sobreescribir los siguientes métodos:
    public void onDrawerClosed(View arg0) {
        actionBar.setTitle("EJ ActionBar");
    }
 
    public void onDrawerOpened(View arg0) {
        actionBar.setTitle("Menu Principal");
    }

    public void onDrawerSlide(View arg0, float arg1) {}

    public void onDrawerStateChanged(int arg0) {}
El primer método y el segundo son llamados cuando el menú de navegación es abierto o cerrado. En este caso simplemente modificamos el titulo de la ActionBar.

El tercer método es llamado cuando cambia la posición del menú de navegación. Como parámetros tenemos la vista hija que a sido movida.

Y el cuarto y ultimo método es llamado cuando hay un cambio de estado de movimiento en el menú de navegacion. Como parámetro tenemos el nuevo estado de movimiento del menú. Este nuevo estado puede ser (STATE_IDLE, STATE,DRAGGING, STATE_SETTLING).



4. Creacion de pestañas (Tabs)

Crear pestañas o tabs en nuestra aplicación puede ser una buena practica de cara al usuario, le ayudara a explorar nuestra aplicación y le sera fácil cambiar entre las diferentes vistas rápidamente. Comentar que cuando el tamaño de pantalla es lo suficientemente grande (normalmente pantalla en modo landscape o tablets) estas pestañas aparecen dentro de la ActionBar junto a los elementos de acción. Por otro lado cuando el tamaño de pantalla es reducido (smartphones con pantalla pequeña) estas pestañas suelen aparecer en barra separada justo debajo de la ActionBar.



A continuación vamos a ver como crear tabs de una manera muy sencilla. Lo primero que nos dice la documentación Android es que tenemos que implementar la interface "ActionBar.TabListener" por lo tanto crearemos la siguiente clase para ello:
public class TabsListener <T extends Fragment> implements TabListener {

    private Fragment fragment;
    private final String tag;
     
    public TabsListener(Activity activity, String tag, Class<T> cls) {
        this.tag = tag;
        fragment = Fragment.instantiate(activity, cls.getName());
    }
     
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        ft.replace(android.R.id.content, fragment, tag);
    }
     
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(fragment);
    }
     
    public void onTabReselected(Tab tab, FragmentTransaction ft) {}
    
}
Esta clase sera la encargada de manejar los eventos que tengan lugar en las pestañas o tabs. Al implementar la interface "ActionBar.TabListener" debemos sobreescribir los métodos "onTabSelected()", "onTabUnselected()" y "onTabReselected()" que practicamente el nombre lo dice todo.

En este caso cuando se seleccione una pestaña simplemente reemplazamos el fragmento y establecemos  la view de ese fragmento. Para las pestañas que no están seleccionadas simplemente eliminamos ese fragmento y por lo tanto su view. De esta manera lo que estamos haciendo es que se cargue la view de un fragmento cada vez que pulsamos una pestaña y para las pestañas no seleccionadas se elimine la view de cada fragmento. No es la manera mas practica pero es un buen comienzo.

Lo siguiente que tenemos que hacer es crear los fragmentos, por cada pestaña que queramos incluir en la aplicación tendremos que crear un fragmento. En este caso solo voy a exponer como se crea un fragmento pero en la aplicación del final del articulo lo vereís con tres. Por lo tanto vamos a crear una nueva clase que extienda de "Fragment":
public class Fragment_Productos extends Fragment {
 
    public View onCreateView(LayoutInflater inflater, 
        ViewGroup container, Bundle savedInstanceState) {
  
        View rootView = inflater.inflate(R.layout.fm_productos, container, false);
  
        TextView texto = (TextView) rootView.findViewById(R.id.texto_productos);
  
        texto.setText("Tab seleccionada" + "\n\n" + "Productos");;
  
        return rootView;
    }
 
}
Esta clase también es muy simple, os recomiendo echarle un ojo a los fragmentos porque tiene bastantes mas posibilidades de las que se exponen aquí. En este caso hemos creado previamente un layout "fm_productos" en el que simplemente ponemos un texto en medio de la view.

Una vez creado el layout pasamos a la clase "Fragment_Productos" que extendemos de "Fragment". Dentro de la clase simplemente sobreescribimos el método "onCreateView()" que sera el encargado de crear la vista cada vez que pulsemos en una pestaña. Dentro del método simplemente inflamos el layout creado previamente, configuramos el texto y establecemos un nuevo texto.

Recordar que tendríamos que repetir este paso por cada pestaña que creemos para nuestra aplicación. Ya por ultimo solo nos queda crear nuestra activity, dejo el código y lo explicamos debajo:
public class CrearTabs extends ActionBarActivity {
 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
  
        ActionBar actionBar = getSupportActionBar();
  
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        /**CREAR TABS**/
        Tab tab = actionBar.newTab()
                    .setText(R.string.productos)
                    .setTabListener(new TabsListener(
                    this, "productos", Fragment_Productos.class));
        actionBar.addTab(tab);

        ....
        ....
        ....

    }
}
Al crear nuestra activity extendemos la clase "ActionBarActivity" y sobreescribimos el método "onCreate()". Dentro del método creamos el objeto ActionBar y ponemos el modo de navegación de la ActionBar en modo pestañas o tabs.

Y ya para terminar tendríamos que crear tantas pestañas como fragmentos hayamos creado. Para crear una nueva pestaña utilizamos el método "newTab()" al que le indicamos el texto a mostrar en la pestaña a traves del metodo "setText()". También podríamos indicarle un icono a mostrar a través del método "setIcon()" pero no es el caso. Seguimos creando el listener para esa pestaña, aquí es donde entra la clase creada al principio de este punto. Por lo tanto creamos el listener para esa pestaña a través del método "setTabListener()" y le aplicamos un nuevo TabsListener indicando los parámetros del constructor de esta clase, (una activity, un tag o identificador, y la clase o fragmento). Para concluir tendremos que añadir la nueva pestaña creada a la actionbar a través del método "addTab()".

Si todo nos a salido bien como resultado podremos obtener algo parecido a esto:



Como se comentaba al principio de este punto, dependiendo de si tiene espacio se mostraran las pestañas en nuevo panel (imagen superior) o incluidas en el ActionBar (imagen inferior).


4.1 Crear views deslizantes

Quizás no sea el termino mas correcto pero mas o menos se entiende, realmente se le llama paginación horizontal. El caso es que la idea es poder cambiar de vista deslizando el dedo de un lado a otro. La documentación Android nos dice que para crear este tipo de vista tenemos que utilizar un "ViewPager" disponible a través de la librería de compativilidad v4.

Así que empezamos creando este layout:
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

El siguiente paso es crear las vistas que incluirá ese ViewPager. Para ello es necesario utilizar un "PagerAdapter" y Android nos ofrece dos posibilidades:
  1. FragmentPagerAdapter: es la clase mas indicada para crear un numero determinado de vistas
  2. FragmentStatePagerAdapter: clase mas indicada para cuando tenemos un numero indeterminado de vistas, automáticamente Android ira destruyendo fragmentos que no estén a la vista reduciendo el consumo de memoria.
En este caso vamos a partir del ejemplo anterior y vamos a adaptar los mismos fragmentos. Por lo tanto vamos a crear una clase que extienda de "FragmentPagerAdapter" estableciendo un numero determinado de tres vistas (en la aplicación del final de articulo podréis observarlo).
public class PagerAdapter extends FragmentPagerAdapter {

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    public Fragment getItem(int arg0) {
        switch (arg0) {
            case 0:
                return new Fragment_Productos();
            case 1:
                return new Fragment_Clientes();
            case 2:
                return new Fragment_Pedidos();
            default:
                return null;
        }
    }

    public int getCount() {
        return 3;
    }

}
Creamos nuestro adaptador y al extender "FragmentPagerAdapter" nos obliga a crear un constructor (que en este caso no lo usaremos, por lo tanto lo dejamos tal cual), y deberemos sobreescribir los métodos "getItem()" y "getCount". Con el primer método le estamos indicando que cuando tenga que cargar dicha vista nos cree un nuevo fragmento. Y con el segundo método simplemente le devolvemos el numero de vistas.

De esta manera siempre tendrá cargado en memoria el fragmento o pestaña que este visible en pantalla y también el mas cercano a la derecha e izquierda, el resto de pestañas o fragmento no existirán hasta que no nos acerquemos a ellos.

Para terminar tendremos que configurar el onCreate de nuestra activity principal por lo tanto pongo el código y luego lo explico un poco:
public class CrearTabsSwipe extends FragmentActivity {

    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.tabs_swipe);
  
        PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());
        ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(adapter);
}
Aquí simplemente establecemos el layout creado previamente a través del método "setcontentView()". Y creamos un objeto de nuestra clase (PagerAdapter) que utilizaremos como adaptador de las vistas. Ya por ultimo configuramos el "ViewPager" de nuestro layout y le aplicamos el adaptador.

El resultado serán estas tres vistas, conforme deslicemos el dedo veremos una u otra y siempre tendrá cargada en la memoria la vista mas cercana a la que se vea en pantalla:


Comentar un par de cosas, la ActionBar es visible porque hemos configurado el botón volver a través del AndroidManifest. Y las tabs o pestañas no están presentes porque simplemente hemos creado una paginación horizontal. En el siguiente punto vamos a ver como añadir las tabs para estas vistas.


4.2 Crear tabs para ViewPager

En este punto vamos a partir del ejemplo anterior donde habíamos creado tres vistas. Vamos a crear una tab o pestaña por cada vista que al pulsarla nos mostrara la vista de esa pestaña. A parte también tendrá implementado el sistema de paginación horizontal, cada vez que deslicemos a un lado o a otro nos mostrara una vista y cambiara automaticamente la pestaña.

Para empezar tenemos que modificar nuestra activity e implementar alguna cosilla mas, la dejo y se explica abajo:
public class CrearTabsSwipe extends ActionBarActivity implements 
                                            ActionBar.TabListener, OnPageChangeListener {

    private ViewPager mViewPager;;
 
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.tabs_swipe);
  
        PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(adapter);
        
        mViewPager.setOnPageChangeListener(this);
        
        ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
  
        Tab tab = actionBar.newTab().setText(R.string.productos).setTabListener(this);
        actionBar.addTab(tab);

        ...
        ...
        ... 
    }
}
Primeramente empezamos cambiando la extensión de la clase por "ActionBarActivity" para poder hacer uso de las tabs. Implementamos las dos interfaces "ActionBar.TabListener" y "OnPageChangeListener" que mas abajo explicare sus métodos obligados.

El código es practicamente le mismo hasta el metodo "setOnPageChangeListener()" que le aplicamos a nuestro ViewPager. Y los pasos siguientes también se han visto anteriormente. Se crea el objeto actionBar para ponerlo en modo tabs y creamos las tres pestañas aplicándoles el listener a través del "this"

Ahora vamos con las intefaces muy sencillas también, primero con "ActionBar.TabListener":
    public void onTabSelected(Tab arg0, FragmentTransaction arg1) {
        mViewPager.setCurrentItem(arg0.getPosition());
    }
 
    public void onTabReselected(Tab arg0, FragmentTransaction arg1) {}
 
    public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {}
Esta interface la hemos visto antes así que simplemente diré que utilizamos el método "setTabSelected()" para que cuando el usuario pinche en una tab o pestaña nuestro ViewPager cambie automaticamente de vista.

La siguiente interface es "OnPageChangeListener":
    public void onPageSelected(int arg0) {
        getSupportActionBar().setSelectedNavigationItem(arg0);
    }
 
    public void onPageScrollStateChanged(int arg0) {}
 
    public void onPageScrolled(int arg0, float arg1, int arg2) {}
Esta interface también utiliza tres métodos y en este caso solo haremos uso del primero que se utiliza cuando una vista se muestra en pantalla al deslizar de un lado a otro. Nosotros dentro del método le estamos diciendo que cambie de tab y ponga la correspondiente.

El siguiente método "onPageScrollStateChanged" se utiliza para controlar el estado de desplazamiento, es decir, podríamos controlar el puntero del usuario al cambiar de vistas y preguntar cuando empieza a deslizar, cuando esta deslizando y cuando a terminado de deslizar una vista.

Y el ultimo método "onPageScrolled" lo podremos utilizar para controlar cuando una vista se esta desplazando.

El resultado sera el mismo del punto anterior pero en este caso tendremos pestañas que cambian según el usuario deslice la vista de un lado a otro e incluso el usuario podrá seleccionar las pestañas y se mostrara su contenido automaticamente. La imagen muestra el resultado:



4.3 Utilizar view desplazable

En este punto vamos a ver como crear lo que muestra la siguiente imagen:


En este caso en vez de utilizar pestañas, simplemente es una barra de información donde le indicara al usuario en que vista esta ubicado. Esta barra de información se ira deslizando conforme el usuario vaya deslizando las vistas o fragmentos.

Primero tendremos que crear el layout, es muy similar al del punto anterior:
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:textColor="#000"
        android:paddingTop="4dp"
        android:paddingBottom="4dp" />

</android.support.v4.view.ViewPager>
Seguimos utilizando la clase "ViewPager" pero en este caso le añadimos un "PagerTitleStrip" que nos servirá para establecer la vista de la imagen de arriba. Podemos controlar su gravedad a través del atributo "layout_gravity" para ponerlo en el top (arriba) o en el bottom (abajo).

El siguiente paso es crear un adaptador y vamos a coger el del punto 4.1 (PageAdapter y le vamos a añadir el siguiente código, dentro de su clase como si fuera otro método mas de la clase:
public CharSequence getPageTitle(int position) {
    String titulo = null;
    switch (position) {
        case 0:
            titulo = "PRODUCTOS";
            break;
        case 1:
            titulo = "CLIENTES";
            break;
        case 2:
            titulo = "PEDIDOS";
            break;
    }
    return titulo;
}
Este método sera el encargado de poner el titulo en el nuevo panel informativo que estamos creando. Comentar que seguimos utilizando los tres fragmentos de siempre (en el código fuente lo viereis claro).

Para terminar crearemos nuestra activity que viene siendo la misma que hemos creado en los puntos anteriores:
public class CrearTabsSwipe2 extends ActionBarActivity {
 
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.tabs_swipe_dos);
  
        PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());
        ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(adapter);
    }
}



5. Aplicar estilo a la ActionBar

Una buena manera de crear los recursos de iconos para nuestra ActionBar (ya sea para elementos de accion o tabs) es utilizar la herramienta: ActionBar and Tab Icon Generator

También podemos crear los recursos del icono del menú de navegación o Navigation Drawer a través de la siguiente herramienta: Navigation Drawer Indicator Generator

Y para terminar recomiendo crear un tema para nuestra ActionBar a través de la herramienta: ActionBar Style Generator. Indicando en "Style compatibility" que sea un tema para "AppCompact", de esta manera conseguiremos que sea compatible con versiones anteriores de Android.

Una vez creado el tema para nuestra ActionBar tendremos que descomprimir e incluir todas las carpetas en nuestro proyecto. Teniendo esa base podremos modificar cualquier cosa a nuestro gusto a parte de aprender como se modifica cada cosa de la ActionBar.

Un ejemplo de lo que podríamos hacer con esto es el siguiente:




6. Código fuente del articulo

Aquí os dejo practicamente todo lo que se a visto en el articulo en forma de aplicación un poco simple, pero con esta base aprenderemos a manejar bastante bien la ActionBar +Tabs y sus posibilidades.

DESCARGAR: EJEMPLO ACTION BAR & TABS



50 comentarios:

  1. Te felicito Luis, que gran trabajo presentas en tu Blog. Para los que iniciamos este camino tan dificil de crear una aplicaión android y no morir en el intento. Mil gracias por la información. Está muy bien explicado todo, paso a paso.

    ResponderEliminar
  2. (y) great!, awesome. Solo falto como aplicar style/font al texto de las tabs on ActionBar

    ResponderEliminar
  3. ¡Qué sencillo parece explicado por ti!
    Mi más sincera enhorabuena y eterna gratitud.

    ResponderEliminar
  4. Chapó!! Gran trabajo y gracias por el esfuerzo y tiempo dedicado.

    ResponderEliminar
  5. Gracias a todos por los comentarios !!

    ResponderEliminar
  6. Hola un gran tutorial, estoy intentado hacer un botón de compartir y otro de favoritos y en este tutorial tenias pensado hacer uno de compartir pero al final lo cambiaste ( solo dejaste la imagen para ver como es ) ¿podrías hacer uno sobre estos dos botones por favor?

    gracias

    ResponderEliminar
    Respuestas
    1. El boton compartir del punto 2.7 se corresponde con el siguiente enlace: (Adding an Action Provider) http://developer.android.com/guide/topics/ui/actionbar.html#ActionProvider.

      El siguiente ejemplo esta sacado de mi aplicacion "Club Voleibol Teruel", y consiste en enviar unos datos con un enlace hacia Google Play para descargar mi app:

      Intent intent = new Intent(Intent.ACTION_SEND);
      intent.setType("text/plain");
      intent.putExtra(Intent.EXTRA_TEXT, "Descargate la nueva aplicacion del Voleibol Teruel:\nhttps://play.google.com/store/apps/details?id=com.datohosting.clubvoleibolteruel");
      startActivity(intent);

      Todo es cuestion de saber lo que quieres compartir y crear un intent con todos los parametros necesarios.

      Eliminar
  7. Hola, tengo un problema al agregar la librería, cuando le doy a propiedades del proyecto para seleccionar la librería, me aparece con una cruz roja y ne me la agrega sabéis por que pasa eso???

    ResponderEliminar
    Respuestas
    1. Por lo poco que acabo de leer en google debes tener algún tipo de problema con las rutas donde están ubicados el proyecto y la librería. O incluso el propio workspace te esta dando el problema.

      Eliminar
  8. Antes de nada me gustaría darte las gracias por este magnifico tutorial, me ha sido de gran ayuda. Ahora querría plantearte un problema que tengo para ver si me puedes ayudar a solucionarlo.

    Como se puede ver en las imagenes que te adjunto a continuación el navigation drawer me aparece siempre por detrás del contenido de las pestañas. He seguido este tutorial y solamente me falla en ese punto.

    Muchas gracias.

    https://www.dropbox.com/s/75y8vc174uzhlxe/Screenshot_2014-01-01-17-40-56.png
    https://www.dropbox.com/s/t331lymjqrf2crv/Screenshot_2014-01-01-15-08-46.png
    https://www.dropbox.com/s/uoztu55j8vfvsdx/Screenshot_2014-01-01-15-08-59.png

    ResponderEliminar
    Respuestas
    1. Lo único que se me ocurre es que estés mezclando el layout del navigation drawer junto con el layout de la propia activity. Crea un layout independiente para el navigation drawer.

      Eliminar
  9. De verdad, que es uno de los mejores artículos que he conseguido en la web, para aprender Android! Muchisimas gracias... Ya tienes un lector más de este tremendo blog. Saludos desde Venezuela!

    ResponderEliminar
  10. Hola Luis te felicito por el tutoríal muy bien explicado, pero tengo un problema, por razones que no vienen al caso no tengo pc y desarrollo para Android con la app AIDE y cuando cargo el codigo fuente que as dejado me da errores en los archivos "styles" ej: "parent="@style/Theme.AppCompat.Light.DarkActionBar" y cosas asi, en total me marca 27 errores. Si encuentras la manera de solucionarlo seria de gran ayuda. Gracias

    Nota: tengo android 2.3.7

    ResponderEliminar
    Respuestas
    1. Hay que incluir la librerira de compatibilidad del punto 1 para que funcione la aplicacion sino no vas a poder ejecutarla. No sabria decirte si se puede incluir desde AIDE ya que no lo he usado nunca.

      Eliminar
  11. LLevo unas semanas luchando por aprender a programar en Android, y lo que he conseguido es sin duda gracias a ti. Te debo una enorme. Gran trabajo. ;)

    Pero tengo una duda, quizá sea algo básico pero llevo unos días que me trae por el camino de la amargura y no he encontrado la solución aún:

    a la hora de declarar la función de un botón o de un spinner dentro de fragment, ¿cómo se haría? Porque al hacerlo en el onCreate del MainActivity la aplicación se detiene, y si lo hago en la clase correspondiente al fragmento, se detiene la aplicación igualmente.

    Muchas gracias por su tiempo en ayudar a los demás. Enhorabuena. :)

    ResponderEliminar
    Respuestas
    1. Partiendo de que los fragmentos son partes independientes de una activity, la interface de usuario utilizada en el fragment debe ser configurada en su clase fragment. Una vez configurada la clase fragment es cuando puedes añadirla a una vista de la activity.

      Para configurar la vista del fragmento se utiliza el metodo onCreateView que se encarga de devolver la vista del fragmento y por lo tanto donde se debe configurar el layout del fragmento, Te dejo un pequeño ejemplo:

      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

      View view = inflater.inflate(R.layout.list_layout, container, false);
      Spinner spin = (Spinner) view.findViewById(R.id.category);

      return view;
      }

      Eliminar
  12. Sólo tengo una palabra para este tutorial: CHAPÓ; en el tutorial, en su contenido y en la manera de explicarlos.
    Instalé todo y sin problemas, hasta que intento descargar con el Sdk Manager el: Android Sdk Tools rev. 22.6.1; y es cuando viene el siguiente problema:
    Failed to rename directory C:\Program Files\Android\android-studio\sdk\tools to C:\Program Files\Android\android-studio\sdk\temp\ToolPackage.old01.
    [find_lock] Directory locked by cmd.exe;java.exe
    Se descarga todo (incluido extras) excepto este.
    He intentado abrir el programa como administrador; nada.
    Sólo tengo abierto el Andoid. Studio y nada. de nada
    La versión de java (reconocida) mediante cmd es la 1.8.0, pero cuando tenía la 7 ocurría igual.
    Y abusando de tu paciencia: Es posible tener dos iconos ?, uno para cuando se instale la app en el dispositivo y otro que aparece en las activitys.
    Gracias,

    ResponderEliminar
    Respuestas
    1. Para el error del sdk he encontrado este hilo, espero que te ayude: http://stackoverflow.com/questions/8839255/failed-to-rename-directory-tools-to-temp-toolpackage-old01-in-c-android-sdk-win

      Para establecer el icono de la aplicacion se hace desde el AndroidManifest.xml indicando el atributo "android:icon=..." normalmente ya viene por defecto. En el caso de la actionBar sino indicamos nada, coge automaticamente ese icono, por lo tanto para cambiarlo utilizaremos el metodo actionBar.setIcon(Drawable);

      Eliminar
  13. Hola muy buen aporte.

    tengo un problemiya, tengo echo tu ejemplo adaptado a mi app, tengo un main_activity con dos pestañas, tab1 y tab2 que extienden de fragment, en tab1 llama a mi actividad principal listado de precios que vas introduciendo en un list view, tengo una funcion para guardar el array de string que se usa para insertar los items en el last view, pero no me funciona, el codigo es este.
    para gravar:
    private void AlmacenarInfo (){
    try
    {
    OutputStreamWriter fout= new OutputStreamWriter( openFileOutput("USUARIOS.TXT", Context.MODE_PRIVATE));

    for (int Ind = 0; listView.getCount() > Ind;Ind++){
    fout.write (listaContactos.get(Ind).getNombre().toString()+"\n");
    fout.write (listaContactos.get(Ind).getImporte().toString()+"\n");
    }
    fout.close();
    }
    catch (Exception ex)
    {
    Log.e("Ficheros", "Error al escribir fichero a memoria interna");
    }
    }

    para leer:
    public void LeerInfo (){
    try
    {
    BufferedReader fin = new BufferedReader(new InputStreamReader(openFileInput("USUARIOS.TXT")));

    String LineaNom = fin.readLine();
    String LineaImp = fin.readLine();

    while ( LineaNom != null && LineaNom != null) {

    listaContactos.add(new EntradaLista (LineaNom,LineaImp));
    LineaNom = fin.readLine();
    LineaImp = fin.readLine();
    }
    //InpNombre.setText(fin.readLine()+fin.readLine());
    fin.close();
    }
    catch (FileNotFoundException ex){
    Log.e("Ficheros", "Error al abrir fichero desde memoria interna");
    }
    catch (Exception ex){
    Log.e("Ficheros", "Error al leer fichero desde memoria interna");
    }


    }

    el error que me da es "The method openFileOutput(String, int) is undefined for the type Cuentas" y "The method openFileInput(String) is undefined for the type Cuentas"

    que me falla gracias.
    Saludos.
    Javier,,

    ResponderEliminar
    Respuestas
    1. Se cual es el problema pero haber si se explicarlo para que lo comprendas. Partimos de que dichos metodos pertenecen a la clase "Context".

      Si por ejemplo los utilizamos directamente en una activity no habria problema porque la propia activity tiene su contexto o Context.

      Por otro lado si los utilizamos en una clase personalizada exactamente como lo quieres hacer tu, necesitamos un objeto Context para poder utilizar esos metodos.

      Por lo tanto puedes agregar al constructor de la clase "Cuentas" otro parametro adicional:

      private Context mContext:

      public Cuentas(Context context) {
      mContext = context;
      }

      private void AlmacenarInfo() {
      mContext.openFileOutput.......
      }


      Luego al crear el objeto de dicha clase le pasas el contexto

      Cuentas mCuentas = new Cuentas(getAplicationContext());

      Eliminar
  14. Hola Luis, gran tutorial pero leyéndolo me ha surgido una duda.

    En el apartado 4.1 Crear views deslizantes dices:

    "Creamos nuestro adaptador y al extender "FragmentPagerAdapter" nos obliga a crear un constructor (que en este caso no lo usaremos, por lo tanto lo dejamos tal cual), y deberemos sobreescribir los métodos "getItem()" y "getCount". Con el primer método le estamos indicando que cuando tenga que cargar dicha vista nos cree un nuevo fragmento. Y con el segundo método simplemente le devolvemos el numero de vistas.

    De esta manera siempre tendrá cargado en memoria el fragmento o pestaña que este visible en pantalla y también el mas cercano a la derecha e izquierda, el resto de pestañas o fragmento no existirán hasta que no nos acerquemos a ellos."


    Entonces me ha surgido una duda, hay algún método del pageadapter que haga que estén cargados un número determinado de fragments en memoria?? de este modo la iteración entre ellos sería más rápida...

    ResponderEliminar
    Respuestas
    1. Gracias por comentar, me ocurrio lo mismo hace tiempo en un proyecto que hice.

      El metodo en cuestion se llama "setOffscreenPageLimit" y pertenece a la clase "ViewPager".

      Te dejo un enalce con la informacion de dicho metodo:
      http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)

      Eliminar
  15. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  16. Buenas, me he ayudado de este artículo para usar actionbar y tabs en mi aplicación. Cuando cambio de pestaña deslizando si se actualiza la pestaña pero cuando lo hago pulsando en la etiqueta de la pestaña no se actualiza y no sé por qué puede ser. No sé si debería hacerlo automáticamente o es que hay que añadir algo más a la clase TabListener para que funcione o es que estoy haciendo algo mal.
    Gracias y enhorabuena por el gran artículo.

    ResponderEliminar
    Respuestas
    1. Utilizando el punto 4.1 y 4.2 no deberias tener problema

      Eliminar
  17. Hola,
    Primero enhorabuena por el blog y gracias, me esta sirviendo mucho para entender ActionBar.
    Pero tengo un problema, quiero crear un menú de navegación (punto 3), primero creo el DrawerLayout y perfecto, pero a la hora de crear la clase "CrearCajon" (que pones tu en foto) no se si eso que va en esa clase, iria en mi clase principal, o tendria que crear una nueva clase.
    si tuviera que ir en mi clase principal, entiendo que habria que meter todo lo del OnCreate(de tu clase CrearCajon) dentro del OnCreate de mui clase principal...
    ¿Pdrías resolverme esta duda?
    y por otro lado, cuando pones esto:
    super.onCreate(savedInstanceState);
    setContentView(R.layout.cajon);

    String[] valores = getResources().getStringArray(R.array.cajon);
    cajon = (DrawerLayout) findViewById(R.id.drawer_layout);
    ListView opciones = (ListView) findViewById(R.id.left_drawer);
    opciones.setAdapter(new ArrayAdapter(this, R.layout.plantilla_cajon, valores));
    el r.layout.cajon --> hace referencia al drawerlayout??
    o seria el drawerlayout el r.layoput.plantilla_cajon??

    Un saludo y disculpa las molestias

    ResponderEliminar
  18. A la hora de crear el Cajon, si te fijas en el primer layout del punto 3, El "FrameLayout" sera lo que se vea en la pantalla y el "ListView" corresponde al cajon. Por lo tanto va todo en la misma clase a no ser que utilices fragmentos para separar las cosas.

    La segunda duda si te fijas bien, se esta creando un adapter. Un adapter necesita de una view y los datos. La view la obtenemos con "R.layout.plantilla_cajon" y los datos es la variable "valores". No tiene nada que ver con el "drawerLayout". Al drawerLayout lo referenciamos al crear el listview.

    ResponderEliminar
  19. Hola Luis,

    Tengo un problema al dividir el actionbar, me funciona bien en pantalla normal , ya que me aparecen los botones en la parte de abajo al utilizar "splitActionBarWhenNarrow", pero cuando giro la pantalla (Control+F12) se suben los botones a la parte de arriba ¿Alguna idea?

    Un saludo y gracias por adelantado

    ResponderEliminar
  20. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  21. Hola de nuevo,
    Ya he podido solucionar lo anterior, quería preguntarte si sabes como customizar los Tabs de action bar tab, he encontrado algunos ejemplos pero usan TabActivity que esta en desuso y los ejemplos que he encontrado solo son con "ActionBar and Tab Icon Generator" pero lo que yo quiero es añadir una imagen en el Tab en lugar de texto y que el focus sea en todo el Tab, no solo en la parte inferior a si como hacerlo mas pequeño.

    ResponderEliminar
  22. Hola Un gran aporte super util!!!

    Pero tengo una duda ¿se puede poner un AB dentro de un fragment?

    ResponderEliminar
  23. Tengo un problema con el ActionBar Style Generator , a la hora de pulsar el botón para descargar no me hace nada

    ResponderEliminar
  24. Exelente articulo... lo pondré en practica :D sigue asi!

    ResponderEliminar
  25. actionBar.setDisplayHomeAsUpEnabled(true); da null pointer cuando ejecuto con sdk 19.

    ResponderEliminar
  26. MUY BUENO EL ARTICULO!!!... Muchas gracias.

    ResponderEliminar
  27. Buenas tardes, ante todo, excelente post, super explicativo, he descargado el codigo fuente para ejecutarlo en eclipse y aunque ya agregue la libreria como lo indicas en el paso 1, me da error en todas las clases como si no las reconociera... Me pide importarla pero aunque la importa sigue mostrando el error, sabrias que causa este problema??

    ResponderEliminar
  28. Un artículo espectacular, muchísimas gracias! La importación a Android Studio / Gradle del código de ejemplo funciona de maravilla, así que entre eso y la excelente explicación este tutorial es una joya :)!

    ResponderEliminar
  29. Hola excelente articulo luis, pero tengo una duda si quisiera llenar un listview desde una base de datos en un fragment como podria hacerlo? Ya que es muy distinto del activity

    ResponderEliminar
  30. Buenas a todos!!!

    Alguien sabe porque cuando hago ActionBar actionBar = getSupportActionBar(); me pone incompatible types ???

    Gracias por vuestra ayuda!!!

    ResponderEliminar
  31. Buenas tardes, te cuento que soy totalmente nuevo en Android, pero me intereso mucho el articulo. Te cuento mi problema.. baje el Codigo Fuente, lo importe en Android, agregue la libreria del paso 1.. y desaparecieron todos los errores que me daba.. pero cuando ejecuto el codigo en debug me tira Source Not Found. Tendrias alguna idea de que estoy haciendo mal ?

    Desde ya muchas gracias!.
    Diego Biasatti. / diego_biasatti@hotmail.com

    ResponderEliminar
  32. Wow! no habia encontrado algo tan bien explicado. esto se me hacia complicado y encontre todo aca.!! muchas gracais

    ResponderEliminar
  33. Buenas,
    Soy nueva en android y tu blog me ha ayudado mucho. Queria saber como se puede unir el drawer layout con las views deslizantes.
    Te cuento mi caso.
    Quiero que en las views deslizantes este productos, ofertas,... y en el drawer layout el login y el enlace de registro.
    No se como unirlos.
    Espero que me puedan ayudar.

    Gracias.

    ResponderEliminar
  34. Brother el link del codigo se cayo !! . . please subelo de nuevo njg_3h@hotmail.com

    ResponderEliminar
    Respuestas
    1. Enlaces resubidos en todos los artículos. Disculpar las molestias

      Eliminar
  35. Buen documento de lectura!
    Pero tengo un problema. Necesito poner un actionBar en mi aplicación, pero tengo una clase que ya extiende de FragmentActivity (uso un viewPager).
    No se puede extender de actionBar y de FragmentActivity a la vez (ni extender de dos o más). Entonces como la pongo?

    ResponderEliminar
  36. Que pena la molestia, lo que sucede, es que cuando creo un nuevo proyecto en android sale este error: Couldn´t resolve resource @style/Widget.Holo:light.ActionMode (2 similar errors not ahown) con API 14: Android 4.0

    No soy muy experta en el tema pero si quiero aprender y ya e descargado los SDK y la ultima versión del complemento en JAVA. Agradezco tu colaboración

    Muchas gracias

    ResponderEliminar
  37. el mejor blog que he visto
    te felicito

    ResponderEliminar
  38. Si quisiera poner unas pestañas secundarias debajo de las pestañas que muestras en el tutorial... como se haria?

    ResponderEliminar
  39. Muy bueno, gracias por el excelente material...

    ResponderEliminar
  40. Muy buena explicación, una definición bastante completa.
    Muchas gracias por compartir.



    android tv box comprar

    ResponderEliminar