Crea una interfaz con pestañas de Material Design en Android App
Spanish (Español) translation by Charles (you can also view the original English article)



El equipo de material design de Google define simplemente la funcionalidad de las pestañas en Android de la siguiente manera:
Las pestañas facilitan la exploración y el cambio de vistas.
En este post aprenderás a mostrar pestañas utilizando la API TabLayout y ViewPager. En este práctico tutorial, cubriremos lo siguiente:
- Los componentes
TabLayoutyViewPager. - Los diferentes modos de pestaña: desplazable y fija.
- Cómo mostrar iconos en lugar de texto para los títulos de las pestañas.
- Como extra, también aprenderás a utilizar la función de plantillas de Android Studio para arrancar rápidamente tu proyecto con una interfaz con pestañas.
En nuestro GitHub repo puedes encontrar un proyecto de ejemplo para este tutorial para que puedas seguirlo fácilmente.
Prerrequisitos
Para poder seguir este tutorial, necesitarás:
- Android Studio 3.0 o superior
- Kotlin plugin 1.1.51 o superior
También puedes aprender todos los entresijos del lenguaje Kotlin en mi serie Kotlin desde cero.


KotlinKotlin desde cero: Nulidad, bucles y condicionesChike Mgbemena

KotlinKotlin Desde Cero: Clases y ObjetosChike Mgbemena
Introducción al componente TabLayout
Según la documentación oficial de Android sobre TabLayout, dice
TabLayout proporciona un diseño horizontal para mostrar las pestañas.
El componente TabLayout es uno de los componentes introducidos como parte de los artefactos de diseño de materiales. Además, también está incluido en la biblioteca de apoyo al diseño. En un TabLayout, cuando se selecciona o se toca una pestaña, se muestra al usuario una página diferente (o un fragmento).
El componente TabLayout puede hacer que las pestañas que se muestren funcionen de dos maneras: fijas y desplazables. Si las pestañas son fijas, todas las pestañas se mostrarán en la pantalla al mismo tiempo.
La captura de pantalla de abajo es la última aplicación oficial de WhatsApp para Android (en el momento de escribir este artículo), que utiliza un TabLayout con una configuración de modo fijo.



En las pestañas desplazables, si el número de pestañas es demasiado amplio para la pantalla, el usuario puede deslizar hacia la izquierda o la derecha para ver más pestañas.
Este es un ejemplo de un TabLayout con modo de pestañas desplazables, mostrado en la última versión de la aplicación News & Weather para Android de Google.



Además, la información que aparece en una pestaña puede ser texto, un icono o una combinación de texto e icono. Por ejemplo, la última aplicación de Twitter para Android utiliza iconos en lugar de texto en cada pestaña.



En las siguientes secciones, nos sumergiremos en la codificación de una aplicación sencilla que hace uso de TabLayout con un ViewPager. ¡Vamos a empezar!
El diseño no es sólo lo que parece y lo que se siente. El diseño es cómo funciona. - Steve Jobs
1. Crea un proyecto de Android Studio
Inicia Android Studio 3 y crea un nuevo proyecto (puedes llamarlo TabLayoutDemo) con una actividad vacía llamada MainActivity.



2. Crea los fragmentos (páginas)
Vamos a crear un TabLayout con sólo tres pestañas. Cuando se selecciona cada una de las pestañas, se muestra un fragmento o página de Android diferente. Así que ahora vamos a crear los tres fragmentos de Android para cada una de las pestañas. Comenzaremos con la primera clase de fragmento, y deberás seguir un proceso similar para las dos clases de fragmentos restantes: FragmentTwo.kt y FragmentThree.kt.
Aquí está mi FragmentOne.kt:
1 |
import android.os.Bundle |
2 |
import android.support.v4.app.Fragment |
3 |
import android.view.LayoutInflater |
4 |
import android.view.View |
5 |
import android.view.ViewGroup |
6 |
|
7 |
class FragmentOne : Fragment() { |
8 |
|
9 |
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, |
10 |
savedInstanceState: Bundle?): View? = |
11 |
inflater!!.inflate(R.layout.fragment_one, container, false) |
12 |
|
13 |
companion object { |
14 |
fun newInstance(): FragmentOne = FragmentOne() |
15 |
}
|
16 |
}
|
Aquí está también mi R.layout.fragment_one:
1 |
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" |
2 |
xmlns:tools="http://schemas.android.com/tools" |
3 |
android:layout_width="match_parent" |
4 |
android:layout_height="match_parent" |
5 |
android:orientation="vertical"> |
6 |
|
7 |
<TextView
|
8 |
android:layout_width="match_parent" |
9 |
android:layout_height="match_parent" |
10 |
android:text="FragmentOne" |
11 |
android:gravity="center_vertical|center_horizontal"/> |
12 |
|
13 |
</LinearLayout>
|
3. Agrega el TabLayout y ViewPager
Para empezar a utilizar TabLayout y ViewPager en tu proyecto, asegúrate de importar el soporte de diseño y también el artefacto de soporte de Android-así que añádelos al archivo build.gradle de tu módulo para importarlos.
1 |
dependencies { |
2 |
implementation 'com.android.support:design:26.1.0' |
3 |
implementation 'com.android.support:support-v4:26.1.0' |
4 |
}
|
Además, visita tu archivo res/layout/activlty_main.xml para incluir tanto el widget TabLayout como la vista ViewPager.
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<android.support.design.widget.CoordinatorLayout
|
3 |
xmlns:android="http://schemas.android.com/apk/res/android" |
4 |
xmlns:app="http://schemas.android.com/apk/res-auto" |
5 |
android:id="@+id/main_content" |
6 |
android:layout_width="match_parent" |
7 |
android:layout_height="match_parent" |
8 |
android:fitsSystemWindows="true"> |
9 |
|
10 |
<android.support.design.widget.AppBarLayout
|
11 |
android:id="@+id/appbar" |
12 |
android:layout_width="match_parent" |
13 |
android:layout_height="wrap_content" |
14 |
android:theme="@style/AppTheme.AppBarOverlay"> |
15 |
|
16 |
<android.support.v7.widget.Toolbar
|
17 |
android:id="@+id/toolbar" |
18 |
android:layout_width="match_parent" |
19 |
android:layout_height="?attr/actionBarSize" |
20 |
android:background="?attr/colorPrimary" |
21 |
app:contentInsetStartWithNavigation="0dp" |
22 |
app:layout_scrollFlags="scroll|enterAlways" |
23 |
app:popupTheme="@style/AppTheme.PopupOverlay"/> |
24 |
|
25 |
<android.support.design.widget.TabLayout
|
26 |
android:id="@+id/tab_layout" |
27 |
style="@style/CustomTabLayout" |
28 |
android:layout_width="match_parent" |
29 |
android:layout_height="?attr/actionBarSize" |
30 |
android:layout_gravity="left" |
31 |
android:background="@color/colorPrimary" |
32 |
app:tabGravity="fill" |
33 |
app:tabMode="fixed"/> |
34 |
|
35 |
</android.support.design.widget.AppBarLayout>
|
36 |
|
37 |
<android.support.v4.view.ViewPager
|
38 |
android:id="@+id/view_pager" |
39 |
android:layout_width="match_parent" |
40 |
android:layout_height="match_parent" |
41 |
app:layout_behavior="@string/appbar_scrolling_view_behavior"/> |
42 |
|
43 |
</android.support.design.widget.CoordinatorLayout>
|
Aquí hemos creado un simple TabLayout con el id tab_layout. En nuestro widget XML TabLayout, se puede ver que hemos incluido algunos atributos-como app:tabMode para ser fijo y también app:tabGravity para ser relleno. La propiedad app:tabGravity se utiliza para configurar cómo se mostrarán los elementos de la pestaña para que ocupen el espacio disponible. Establecemos esto como relleno, lo que distribuirá los elementos uniformemente a través del ancho del TabLayout. Ten en cuenta que esto será más visible en pantallas más anchas, como las tablets.
También he incluido un atributo de estilo personalizado (@style/CustomTabLayout) en nuestro widget TabLayout.
1 |
<style name="CustomTabLayout" parent="Widget.Design.TabLayout"> |
2 |
<item name="tabIndicatorColor">@android:color/white</item> |
3 |
<item name="tabIndicatorHeight">3dp</item> |
4 |
<item name="tabBackground">?attr/selectableItemBackground</item> |
5 |
<item name="tabTextAppearance">@style/CustomTabTextAppearance</item> |
6 |
<item name="tabSelectedTextColor">@android:color/white</item> |
7 |
</style>
|
Comenzamos a personalizar nuestro TabLayout estableciendo los valores de los atributos a aplicar en el TabLayout. Aquí están los detalles de algunos de los atributos aplicados:
-
tabIndicatorColor:establece el color del indicador de pestaña para la pestaña actualmente seleccionada. También se puede establecer mediante programación llamando asetSelectedTabIndicatorColor()en una instancia deTabLayout. -
tabIndicatorHeight: establece la altura del indicador de tabulación para la pestaña seleccionada actualmente. Esto también se puede establecer mediante programación llamando asetSelectedTabIndicatorHeight()en una instancia deTabLayout. -
tabSelectedTextColor:establece los colores del texto para los diferentes estados (normal, seleccionado) utilizados para las pestañas. El equivalente de este atributo en Java essetTabTextColors().
Inmediatamente después de crear nuestro widget TabLayout en XML, la siguiente vista fue un ViewPager. La documentación oficial dice lo siguiente sobre ViewPager:
Gestor de diseño que permite al usuario hojear a izquierda y derecha las páginas de datos...
4. Crea el PagerAdapter
Necesitamos crear una subclase en SampleAdapter.kt que extienda el FragmentPagerAdapter. Esta clase es la responsable de gestionar los diferentes fragmentos que se mostrarán en las pestañas.
1 |
import android.support.v4.app.Fragment |
2 |
import android.support.v4.app.FragmentManager |
3 |
import android.support.v4.app.FragmentPagerAdapter |
4 |
|
5 |
class SampleAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { |
6 |
|
7 |
override fun getItem(position: Int): Fragment? = when (position) { |
8 |
0 -> FragmentOne.newInstance() |
9 |
1 -> FragmentTwo.newInstance() |
10 |
2 -> FragmentThree.newInstance() |
11 |
else -> null |
12 |
}
|
13 |
|
14 |
override fun getPageTitle(position: Int): CharSequence = when (position) { |
15 |
0 -> "Tab 1 Item" |
16 |
1 -> "Tab 2 Item" |
17 |
2 -> "Tab 3 Item" |
18 |
else -> "" |
19 |
}
|
20 |
|
21 |
override fun getCount(): Int = 3 |
22 |
}
|
Aquí anulamos tres métodos de la clase padre: getItem(), getCount(), y getPageTitle(). Aquí están las explicaciones de los métodos:
-
getItem(): devuelve unfragmentopara una posición determinada dentro delViewPager. -
getCount(): indica cuántas páginas habrá en elViewPager. -
getPageTitle(): este método es llamado por elViewPagerpara obtener una cadena de título que describa la pestaña especificada.
Por ejemplo, si la pestaña seleccionada es la primera pestaña con el título "Pestaña 1 Elemento", mostrará inmediatamente al usuario una página FragmentOne.
5. Inicialización de componentes
A continuación, vamos a inicializar las instancias de nuestro TabLayout, ViewPager, y SampleAdapter. La inicialización va a ocurrir dentro de onCreate() en MainActivity.kt.
1 |
import android.os.Bundle |
2 |
import android.support.design.widget.TabLayout |
3 |
import android.support.v4.view.ViewPager |
4 |
import android.support.v7.app.AppCompatActivity |
5 |
import android.support.v7.widget.Toolbar |
6 |
|
7 |
class MainActivity : AppCompatActivity() { |
8 |
|
9 |
override fun onCreate(savedInstanceState: Bundle?) { |
10 |
super.onCreate(savedInstanceState) |
11 |
setContentView(R.layout.activity_main) |
12 |
|
13 |
initToolbar() |
14 |
|
15 |
val tabLayout: TabLayout = findViewById(R.id.tab_layout) |
16 |
|
17 |
val viewPager: ViewPager = findViewById(R.id.view_pager) |
18 |
|
19 |
val adapter = SampleAdapter(supportFragmentManager) |
20 |
|
21 |
viewPager.adapter = adapter |
22 |
tabLayout.setupWithViewPager(viewPager) |
23 |
|
24 |
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { |
25 |
override fun onTabSelected(tab: TabLayout.Tab) { |
26 |
|
27 |
}
|
28 |
|
29 |
override fun onTabUnselected(tab: TabLayout.Tab) { |
30 |
|
31 |
}
|
32 |
|
33 |
override fun onTabReselected(tab: TabLayout.Tab) { |
34 |
|
35 |
}
|
36 |
})
|
37 |
}
|
38 |
|
39 |
private fun initToolbar() { |
40 |
val toolbar: Toolbar = findViewById(R.id.toolbar) |
41 |
setSupportActionBar(toolbar) |
42 |
supportActionBar!!.title = "TabLayout Demo" |
43 |
}
|
44 |
}
|
Obtenemos referencias a nuestro TabLayout y ViewPager desde R.layout.activity_main y los inicializamos. También creamos una instancia de nuestro SampleAdapter, pasando una instancia de FragmentManagercomo argumento. Necesitamos proporcionar las vistas para nuestro ViewPager, por lo que llamamos a setAdapter() y le pasamos nuestro adaptador. Finalmente, llamamos a setupWithViewPager() en una instancia de TabLayout para hacer algo de trabajo:
- creación de la ficha necesaria para cada página
- configurar los oyentes necesarios
Cuando el usuario pulsa sobre una pestaña, cambia las páginas en el ViewPager y muestra la página requerida (o Fragmento). Además, al pasar de una página a otra se actualiza la pestaña seleccionada. En otras palabras, este método nos ayuda a ocuparnos del cambio de estado del scroll y de los clics en las pestañas.
La función onTabSelectedListener() se utiliza para incluir un oyente que será invocado cuando la selección de la pestaña cambie. Hemos anulado las siguientes devoluciones de llamada:
-
onTabSelected(): se activa cuando una ficha entra en el estado seleccionado. -
onTabUnselected(): se invoca cuando una ficha sale del estado seleccionado. -
onTabReselected(): se invoca cuando una ficha que ya está seleccionada es elegida de nuevo por el usuario.
Ten en cuenta que también podemos establecer el modo de pestañas mediante programación -en lugar de a través del XML del diseño- utilizando setTabMode() en una instancia de TabLayout. Pasamos el modo (fijo o desplazable) a este método como argumentos. Por ejemplo, podemos pasar TabLayout.MODE_FIXED para un modo fijo o TabLayout.MODE_SCROLLABLE para un modo desplazable.
1 |
tabLayout.tabMode = TabLayout.MODE_FIXED |
2 |
tabLayout.tabMode = TabLayout.MODE_SCROLLABLE |
Ten en cuenta que si deseas crear explícitamente las pestañas en lugar de utilizar el método de ayuda setUpWithViewPager(), puedes utilizar newTab() en una instancia de TabLayout.
1 |
val tabLayout: TabLayout = findViewById(R.id.tab_layout) |
2 |
|
3 |
tabLayout.addTab(tabLayout.newTab().setText("Songs")) |
4 |
tabLayout.addTab(tabLayout.newTab().setText("Albums")) |
5 |
tabLayout.addTab(tabLayout.newTab().setText("Artists")) |
Ten en cuenta también que podríamos crear explícitamente las pestañas a través de XML en lugar de programarlas.
1 |
<android.support.design.widget.TabLayout
|
2 |
android:id="@+id/tabs" |
3 |
android:layout_width="match_parent" |
4 |
android:layout_height="wrap_content"> |
5 |
|
6 |
<android.support.design.widget.TabItem
|
7 |
android:id="@+id/tabItem" |
8 |
android:layout_width="wrap_content" |
9 |
android:layout_height="wrap_content" |
10 |
android:text="Songs"/> |
11 |
|
12 |
<android.support.design.widget.TabItem
|
13 |
android:id="@+id/tabItem2" |
14 |
android:layout_width="wrap_content" |
15 |
android:layout_height="wrap_content" |
16 |
android:text="Albums"/> |
17 |
|
18 |
<android.support.design.widget.TabItem
|
19 |
android:id="@+id/tabItem3" |
20 |
android:layout_width="wrap_content" |
21 |
android:layout_height="wrap_content" |
22 |
android:text="Artists"/> |
23 |
|
24 |
</android.support.design.widget.TabLayout>
|
6. Prueba de la App
Finalmente, ¡puedes ejecutar la aplicación!



Intenta interactuar con la aplicación deslizando el dedo hacia la izquierda o hacia la derecha y tocando las pestañas.
7. Pestañas desplazables
Las directrices oficiales de diseño de materiales sobre las pestañas dicen lo siguiente sobre las pestañas desplazables:
Las pestañas desplazables muestran un subconjunto de pestañas en un momento dado. Pueden contener etiquetas de pestañas más largas y un mayor número de pestañas que las pestañas fijas. Las pestañas desplazables se utilizan mejor para contextos de navegación en interfaces táctiles cuando los usuarios no necesitan comparar directamente las etiquetas de las pestañas.
Veamos cómo crear pestañas con configuración de modo desplazable. Hice el título para cada una de las pestañas más largo que antes. Aquí está el resultado en modo fijo:



Puedes ver que TabLayout ha utilizado múltiples líneas para mostrar cada uno de los títulos de las pestañas. En algunas situaciones, ¡incluso truncará los títulos! Esto crea una mala experiencia para el usuario, así que si los títulos de las pestañas tienen que ser muy largos, deberías considerar usar el modo desplazable. Ten en cuenta también que si vas a tener más de cuatro pestañas, se recomienda hacer el modo de pestañas desplazable.
Cambiemos la propiedad app:tabMode de fijo a desplazable.
1 |
<android.support.design.widget.TabLayout
|
2 |
<!-- ... --> |
3 |
app:tabMode="scrollable"/> |
Recuerda que también puedes establecer el modo de tabulación mediante programación, como se ha comentado anteriormente.



8. Mostrar los iconos de las pestañas
Ahora vamos a ver cómo reemplazar el texto del elemento de la pestaña con iconos.
1 |
class MainActivity : AppCompatActivity() { |
2 |
|
3 |
override fun onCreate(savedInstanceState: Bundle?) { |
4 |
// ...
|
5 |
tabLayout.setupWithViewPager(viewPager) |
6 |
tabLayout.getTabAt(0)!!.setIcon(android.R.drawable.ic_dialog_email) |
7 |
tabLayout.getTabAt(1)!!.setIcon(android.R.drawable.ic_dialog_info) |
8 |
tabLayout.getTabAt(2)!!.setIcon(android.R.drawable.ic_dialog_alert) |
9 |
// ...
|
10 |
}
|
11 |
|
12 |
// ...
|
13 |
}
|
Aquí llamamos a getTabAt() en una instancia de TabLayout. La llamada a este método devolverá la pestaña en el índice especificado. A continuación, llamamos a setIcon(). Al llamar a este método se establecerá el icono que se muestra en esta pestaña.
También he puesto el modo de pestañas como fijo.
1 |
<android.support.design.widget.TabLayout
|
2 |
app:tabMode="fixed"/> |
Todavía reemplazo el getPageTitle() dentro de SampleAdapter.
1 |
class SampleAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) { |
2 |
|
3 |
// ...
|
4 |
|
5 |
override fun getPageTitle(position: Int): CharSequence = when (position) { |
6 |
0 -> "TAB 1" |
7 |
1 -> "TAB 2" |
8 |
2 -> "TAB 3" |
9 |
else -> "" |
10 |
}
|
11 |
|
12 |
// ...
|
13 |
}
|
Aquí está el resultado:



Ahora, si quieres sólo los iconos, simplemente no anulas getPageTitle().



9. Bonificación: Uso de plantillas de Android Studio
En lugar de escribir tanto código para crear una interfaz con pestañas o una actividad desde cero, Android Studio 3.0 tiene algunas plantillas de código preexistentes (disponibles en Java y Kotlin) para ayudar a poner en marcha tu proyecto. Una de estas plantillas se puede utilizar para crear una actividad con pestañas.
Te mostraré cómo utilizar esta práctica función en Android Studio 3.
Para un nuevo proyecto, enciende Android Studio 3.



Introduce el nombre de la aplicación y haz clic en el botón Siguiente.
Puedes dejar los valores predeterminados tal y como están en el cuadro de diálogo Dispositivos Android de destino. Vuelve a hacer clic en el botón Siguiente.



En el cuadro de diálogo Agregar una actividad al móvil, desplázate hacia abajo y selecciona Actividad con pestañas. Haz clic en el botón Siguiente después de eso.



En el último diálogo, desplázate hasta el menú desplegable Estilo de navegación y selecciona Pestañas de la barra de acción (con ViewPager). Por último, haz clic en el botón Finalizar para aceptar todas las configuraciones.
Android Studio nos ha ayudado a crear un proyecto con una actividad con pestañas. ¡Realmente genial!



Se recomienda encarecidamente explorar el código generado.
En un proyecto de Android Studio ya existente, para utilizar esta plantilla, simplemente ve a Archivo > Actividad > Actividad con pestañas. Y sigue los pasos similares a los descritos anteriormente.



Las plantillas que vienen incluidas con Android Studio son buenas para diseños simples y para crear aplicaciones básicas, pero si deseas poner en marcha tu aplicación aún más, puedes considerar algunas de las plantillas de aplicaciones disponibles en Envato Market.
Son un gran ahorro de tiempo para los desarrolladores experimentados, ya que les ayudan a reducir el trabajo de crear una aplicación desde cero y a centrar su talento en las partes únicas y personalizadas de la creación de una nueva aplicación.
Conclusión
En este tutorial, aprendiste a crear una interfaz con pestañas en Android con la API TabLayout y ViewPager desde cero. También exploramos cómo usar fácil y rápidamente las plantillas de Android Studio para crear una interfaz con pestañas.
Recomiendo encarecidamente revisar las pautas oficiales de diseño de material para pestañas para obtener más información sobre cómo diseñar y usar pestañas correctamente en Android.
¡Para obtener más información sobre la codificación para Android, echa un vistazo a algunos de nuestros otros cursos y tutoriales aquí en Envato Tuts+!











