Uso de tabs (pestañas)

Los tabs nos van a permitir crear una interfaz de usuario basada en pestañas, donde, de una forma muy intuitiva, podemos ofrecer al usuario diferentes vistas, que son seleccionadas al pulsar una de las pestañas que se muestran en la parte superior:

 

Para crear una interfaz de usuario con pestañas, es necesario utilizar FragmentTabHostTabWidget. FragmentTabHost debe ser el nodo raíz para el diseño, que contendrá tanto el TabWidget para la visualización de las pestañas, como un FrameLayout para mostrar el contenido. A continuación se muestra el esquema a utilizar:

Nota: En las primeras versiones de Android se usaba TabHosten lugar de FragmentTabHost. A partir del nivel de API 13, TabHost ha sido declarado obsoleto. Google ha reorientado su jerarquía de clases para introducir el concepto de fragment. No obstante, puedes seguir utilizando TabHost sin ningún problema.

Nota: Hasta la vesión 3.0 (API 11) no aparece FragmentTabHost. Entonces, no podría usarse en niveles de API anteriores. Para resolver este problema, y más generalmente para poder usar fragments en versiones anteriores a la 3.0, Google ha creado la librería de compatibilidad[1] (android.support). Se añade por defecto al crear un nuevo proyecto. Por lo tanto, podemos usar fragments y clases relacionadas desde cualquier versión.

<android.support.v4.app.FragmentTabHost
   android:id="@android:id/tabhost" …/>
   <LinearLayout …>
         <TabWidget
               android:id="@android:id/tabs" …/>
         <FrameLayout
               android:id="@android:id/tabcontent" …>
   </LinearLayout>
</TabHost>

Nota: El siguiente vídeo utiliza TabHost en lugar FragmentTabHost. No obstante, los conceptos que se explican siguen siendo válidos.

 

Vídeo[tutorial]: La vista TabHost en Android

Ejercicio paso a paso: Uso de FragmentTabHost

1.     Crea un nuevo proyecto y llámalo Tabs.

2.     Reemplaza el código de activity_main.xml por el siguiente:

<android.support.v4.app.FragmentTabHost
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0"
            android:orientation="horizontal" />
        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>
</android.support.v4.app.FragmentTabHost>

La primera cosa extraña de este código es el nombre de la primera etiqueta. En lugar de indicar simplemente FragmentTabHost, se ha indicado el nombre completo de domínio. Como estudiaremos en el capítulo 4, cada vez que usemos una vista que no sea del sistema (por ejemplo creada por nosotros o creada en una librería como en este caso) tendremos que indicar la clase donde se crea con su nombre completamente cualificado. Es decir, el nombre  de la clase precedida de su paquete. 

Como puedes observar un FragmentTabHost es el nodo raíz del diseño, que contiene dos elementos combinados por medio de un LinearLayout. El primero es un TabWidget para la visualización de las pestañas y el segundo es un FragmentLayout para mostrar el contenido asociado de cada lengüeta. En número de lengüetas y su contenido se indicará por código.

3.     Abre el fichero MainActivity.java y reemplaza el código por el siguiente:

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;

publicclassMainActivity extendsFragmentActivity {

   privateFragmentTabHost tabHost;

   @Override
   protectedvoidonCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     tabHost= (FragmentTabHost) findViewById(android.R.id.tabhost);
     tabHost.setup(this,
                 getSupportFragmentManager(),android.R.id.tabcontent);
     tabHost.addTab(tabHost.newTabSpec("tab1").setIndicator("Lengüeta 1"),
                           Tab1.class, null);
     tabHost.addTab(tabHost.newTabSpec("tab2").setIndicator("Lengüeta 2"),
                           Tab2.class, null);
     tabHost.addTab(tabHost.newTabSpec("tab3").setIndicator("Lengüeta 3"),
                           Tab3.class, null);
    }
}

Observa como la clase creada extiende de FragmentActivity en lugar de Activity. Esto permitirá que la actividad trabaje con fragments; en concreto, vamos a crear un fragment para cada lengüeta. Se han añadido varias líneas en el método onCreate(). Empezamos inicializando la variable tabHost, luego se utiliza el método setup() para configurarla. Para ello indicamos el contexto, manejador de fragments y donde se mostrarán los fragments.

Cada una de las siguientes tres líneas introduce una nueva lengüeta usando el método addTab(). Se indican tres parámetros: un objeto TabSpec, una clase con el fragment a visualizar en la lengüeta y un Bundle por si queremos pasar información a la lengüeta. El método newTabSpec() crea una nueva lengüeta en un TabHost. Se le pasa como parámetro un String, que se utiliza como identificador y devuelve el objeto de tipo TabSpec creado.

Nota sobre Java: Dado que el método newTabSpec() devuelve un objeto de tipo  TabSpec , tras la llamada. podemos llamar al método setIndicator(), que nos permitirá introducir un descriptor en la pestaña recién creada.

NOTA: También podremos asignar iconos a las lengüetas con el método setIndicator(). En el capítulo siguiente se estudiarán los iconos disponibles en el sistema y cómo crear nuevos icono. En las últimas versiones de Android solo podemos visualizar un texto o un icono. Para ver el icono introduce un texto vacío.

4.     Crea un nuevo layout y llámalo tab1.xml:

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical|center_horizontal"
        android:text="Lengüeta 1"
        android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

5.     Crea una nueva clase con Tab1.java:

public class Tab1 extends Fragment {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

    }

 

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

        Bundle savedInstanceState) {

       return inflater.inflate(R.layout.tab1, container, false);

    }

}

Nota sobre Java: Pulsa Alt-Intro en Android Studio o Ctrl-Shift-O en Eclipse para que automáticamente se añadan los paquetes que faltan. Si la clase Fragment se encuentra en más de un paquete, selecciona

android.support.v4.app.FragmentTabHost.

Un fragment se crea de forma muy parecida a una actividad. También dispone del método onCreate(), aunque en este ejemplo no se introduce código. Un fragment también tiene asociada una vista, aunque a diferencia de una actividad, no se asocia en el método onCreate(), sino que dispone de un método especial para esta tarea: onCreateView().

6.     Repite los dos pasos anteriores para crear tab2.xml y Tab2.java.

7.     Repite de nuevo para crear el layout tab3.xml y la clase Tab3.java.

8.     Modifica estos ficheros para que cada layout sea diferente y para que cada fragment visualice el layout correspondiente.

9.     Ejecuta el proyecto y verifica el resultado.

NOTA: Si en uno de los layouts asignados a un fragment has utilizado el atributo onClick, el método indicado ha de ser introducido dentro de la actividad. Si lo introduces dentro del fragment no será reconocido.