Diseñar Temas y Estilos para tus Aplicaciones Android

El diseño visual de una aplicación Android es representado a través de reglas contenidas en Estilos y Temas. Estas herramientas permiten que los programadores y diseñadores generen una interfaz más amigable y personalizada de sus apps, para establecer una identidad que impacte al usuario final.

Por esta razón es necesario que entendamos como se construyen y asignan estilos a tus Views y Layouts. Si sigues leyendo este artículo veras como crear archivos de estilos, los temas que maneja Android por defecto, como personalizar views y varios ejemplos prácticos.

¿Qué es un estilo?

Es un conjunto de reglas que determinan la apariencia y formato de un View o Layout. Si recuerdas las propiedades que muestran los views a la hora de usar la vista de diseño en Android Studio, podrás comprende mejor a que nos referimos con estilos. El color de fondo, cambiar el tamaño del texto, definir el alto y ancho, etc., son características que hacen parte de los estilos.

Aunque las propiedades se pueden especificar en nuestro mismo layout(como lo hemos hecho hasta ahora), es posible independizarlos del diseño a través de un archivo de recurso de estilos. Este concepto es muy similar cuando desarrollamos websites, separando los archivos html de los estilos css.

Implementando estilos en archivos de recursos

Al igual que los strings, layouts y drawables también hay una sintaxis para generar un estilo en un archivo de recurso que nos permita reusar código. Para ello debemos crear un nuevo archivo XML que se albergue en la carpeta de recursos res/values/. Donde usaremos el nodo padre para los recursos <resource>.

Ahora, para definir un estilo usaremos el elemento <style> y le asignaremos un nombre único a través de su atributo name. Para definir las reglas que lo componen crearemos elementos <item> en su interior, detallando el nombre del atributo a modificar y su respectivo valor.

Veamos un ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<resource>
 <style name="buttonStyle">
  <item name="android:layout_width">wrap_content<item/>
  <item name="android:layout_height">wrap_content<item/>
  <item name="android:textColor">#AEC6CF<item/>
 </style>
</resource>

Si deseáramos implementar este estilo en un botón dentro de un layout, entonces referenciamos un acceso a los recursos de estilos con la convención @style/nombreEstilo como se muestra a continuación:

<Button
 style="@style/buttonStyle"
 text="Clickeame"/>

Herencia de estilos

El elemento <style> también puede heredar propiedades de otro estilo a través de su atributo parent. Esta relación permite copiar las reglas del estilo padre y sobrescribir o añadir propiedades. Veamos un ejemplo

<style name="buttonStyle" parent="@style/parentStyle">

Como ves, referenciamos a otro estilo llamado parentStyle.

Cabe aclarar que siempre que creas un nuevo proyecto en Android Studio, el archivo styles.xml es autogenerado con una estructura similar a esta:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <!-- Customize your theme here. -->
    </style>

</resources>

El estilo hereda sus propiedades del estilo padre android:Theme.Holo.Light.DarkActionBar, el cual representa un tema propio del sistema, que indica que se usará las características del tema Theme.Holo.Ligth pero con el estilo para la Action Bar del tema Theme.Holo.

Propiedades de un estilo

Existen gran cantidad de propiedades que podemos usar para un componente. Dependiendo del View o Layout que vayamos a personalizar, así mismo varían sus atributos. La vista de diseño de Android Studio nos permite observar todas las propiedades de un View disponibles para modificar. No obstante puedes ir al sitio oficial de Android y revisar las referencias de cada clase.

¿Qué es un tema?

Un tema es un estilo genérico que se asigna a una aplicación completa o actividad. Esto permite que todos los componentes sigan un mismo patrón de diseño y personalización para mantener consistencia en la UI.

Si deseamos añadir un tema a una aplicación debemos dirigirnos al archivo AndroidManifest.xml y agregar al elemento <application> el atributo theme con la referencia del tema solicitado. Veamos:

<application android:theme="@style/MiTema">

Si fuese una actividad entonces haríamos exactamente lo mismo:

<activity android:theme="@style/TemaActividad">

Si haces una retrospección sobre las aplicaciones que hemos construido a lo largo de estos artículos sobre desarrollo de apps Android, verás que nuestro Android Manifest ha asignado siempre un tema que se encuentra en el namespace del sistema con la referencia @android/style/Theme.Holo.Light.

Eso nos lleva a nuestro siguiente apartado…

Temas y estilos del sistema

Android trae por defecto estilos y temas para todos sus aplicaciones y entorno. Estas reglas de estilos son guardadas en un archivo llamado styles.xml y los temas en themes.xml. Ambos contienen definiciones establecidas por el equipo desarrollador de Android creadas a su gusto y medida.

Antes de la versión 11 se usaba un tema por defecto llamado Theme.Light, pero para las versiones recientes se diseñaron los temas Theme.Holo (Estilo oscuro) y el Theme.Holo.Light (Estilo claro).

De ellos descienden muchas variantes, como por ejemplo el tema Theme.Holo.Light.DarkActionBar.
La siguiente ilustración muestra sus apariencias:

Si deseas implementar estos temas en tu aplicación o actividad simplemente los referencias de la siguiente forma:

<application android:theme="@android/style/Theme.Holo">
<application android:theme="@android/style/Theme.Holo.Light">

Crear tu propio tema

Para facilitar la personalización de un tema nuevo es recomendable extender las propiedades de los temas que Android contiene. Esto nos permitirá ahorrarnos tiempo en definición y escritura, por lo que solo se implementan las reglas que deseamos modificar en particular.

Supongamos que deseamos usar el tema Holo.Light en nuestra aplicación pero deseamos todo el formato de texto itálico Para conseguir este resultado aplicamos el mismo procedimiento que hicimos con los estilos, donde nuestro tema heredará la mayoría de características del tema y solo tendremos que editar el atributo android:textStyle.

<style name="Italic" parent="@android/Theme/Holo/Light">
        <item name="android:textStyle">italic</item>
</style>

 

Usar un estilo según la versión de Android

Si deseas condicionar el uso de tus estilos o temas puedes hacerlo a través de cualificadores. Para que surta efecto este concepto, debemos nominar las carpetas con respecto a la versión. Por ejemplo si deseamos que el estilo se aplique después la versión 14 del SDK entonces usamos el nombre values-v14.

Un cualificador es un factor del cual depende la implementación de nuestros recursos. Esto permite que nuestra aplicación autogenere el código necesario, lo que nos ahorra la molestia de configurar programáticamente el cambio.

Además Android Studio tiene un asistente muy versátil que nos permite crear carpetas tipeadas con facilidad.
Volvamos al caso de la versión 14, si deseas establecer este cualificador entonces realiza lo siguiente:

Ve a tu carpeta de recursos y dentro de ella: presiona click derecho > New >Android resource directory
Android Resource Directory
¿Se ha ejecutado un asistente?, ok, entonces lo que sigue es elegir el tipo de recurso que usaremos (Resource Type). En este caso elegiremos values, que es donde guardamos nuestros estilos. Luego en la lista del lado izquierdo (Avalaible qualifiers) selecciona el cualificador Version (tiene el loguito de Android). Cualificador Version en Android Studio
Ahora selecciona con el botón que indica traslado a la derecha. Seguidamente aparecerá un espacio para que seleccionemos el número mínimo de la versión del API a establecer. Habíamos dicho 14, así que digitamos ese número.Estilos para la versión 14 en adelante
Presiona OK e inmediatamente estará creado nuestro nuevo directorio de recursos destinados solo para las versiones mayores o iguales a 14.Nueva carpeta values
Ahora puedes ubicar tu archivo styles.xml en este directorio y automáticamente tu aplicación condicionará el recurso a ejecutarse cuando sea pertinente.

Los archivos R.style y R.attr

Al usar los estilos del sistema estamos haciendo referencia a los valores que poseen las clases R.style y R.attr.
Estas clases son la referencia programática de los recursos predefinidos por el sistema.

En R.style podemos encontrar un sinnúmero de estilos para nuestros views y en R.attr podemos referenciar los atributos actuales del tema que poseen los views.

Utilidades

A continuación veremos algunas utilidades populares para proyectos de desarrollo:

Cambiar el fondo de nuestras actividades

Es normal que deseemos cambiar el aspecto con que se proyecta una actividad en su interior por un color llamativo o una imagen de fondo. Para hacerlo, acudimos a la propiedad windowBackground.

Los atributos que empiezan por el prefijo window no son aplicables a un view en concreto. Ellos se aplican a una app o actividad como si se tratase de un todo o un solo objeto.

Este atributo recibe por referencia un color solido, una forma o una imagen de nuestros recursos. Normalmente los colores se deben declarar como ítems <color>, cuyo valor es un número hexadecimal.

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
    <item name="android:windowBackground"><strong>@android:color/holo_blue_light</strong></item>
</style>

En este caso usamos un color predefinido por el sistema. El resultado sería este:
Color holo blue como fondo
Si deseas usar tu propio color hacer declaras tu ítem <color> y lo asignas:

<strong><color name="yellowPastel">#FDFD96</color></strong>

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
   <item name="android:colorBackground"><strong>@color/yellowPastel</strong></item>
   <item name="android:windowBackground"><strong>@color/yellowPastel</strong></item>
</style>

Ahora tendríamos el siguiente fondo:
Usando la propiedad background
Para setear una imagen simplemente usamos una referencia drawable como ya hemos hecho antes:

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
   <item name="android:windowBackground"><strong>@drawable/background</strong></item>
</style>

La siguiente ilustración muestra una imagen de fondo:
Imagen en el background

Superponer la Action Bar

En ocasiones deseamos que nuestra Action Bar no interfiera en la visualización de nuestra actividad. Aunque podríamos ocultarla con el método hide(), podemos optar por otro camino al sobreponerla en el fondo de la actividad. Esto nos permitirá contrastarla de forma eficaz.

Para ello solo debemos asignar true a un atributo especial llamado windowActionBarOverlay, el cual permite habilitar la superposición de la Action Bar. Cabe aclarar que este efecto se aplica solo a los temas que se heredan de Theme.Holo.

<style name="AppTheme" parent="android:Theme.Holo">
    <item name="android:windowActionBarOverlay">true</item>
</style>

La anterior descripción produciría un efecto similar al siguiente:
Superposición de la Action Bar
Si deseas que la Action Bar se vea translucida puedes aplicar el siguiente truco:

Crea un estilo propio para la Action Bar y extiéndelo del estilo Widget.Holo.Light.ActionBar.Solid.Inverse. Este permite obtener las características de la Action Bar del Holo.Light con colores inversos, para el contraste correcto entre el background.

Luego cambia el background del estilo y asígnale el siguiente drawable(Click derecho guardar):
NinePatch para action bar
A este tipo de imágenes se les llaman Nine Patch. Son imágenes PNG con una descripción gráfica especial, que posibilitan su expansión dependiendo del tamaño. Se les diferencia por su extensión “.9.png”. Luego veremos más sobre ellos.

Ahora, si aplicáramos este truco sobre el estilo con la barra de acción obscura, el código que tendríamos sería el siguiente:

<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
       
 <item name="android:windowBackground">@drawable/fondo</item> 
   <item name="android:actionBarStyle">@style/ActionBar.Overlay</item>
   <item name="android:windowActionBarOverlay">true</item>

</style>

...

<style name="ActionBar.Overlay"
  parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">

        <item name="android:background">@drawable/actionbar_translucent</item>

</style>

El resultado:
Action bar translúcida

Color del texto

Para cambiar el color del texto tendremos que modificar el atributo textColor y asignarle el valor del color. Veamos:

<style name="TextColor">
<item name="android:textColor">#25383C</item>
</style>

Estilos En Android: Aplicación De Ejemplo

Crearemos una pequeña aplicación que use un tema personalizado. Esta actividad contendrá un formulario hipotético para envío de datos a los suscriptores de Hermosa Programación. La idea es crear un tema que abarque los elementos generales de la aplicación y luego crear estilos para views específicos.
App con estilo personalizado
Para desbloquear el link de descargar del código completo, sigue estas instrucciones:

Veamos como recrear el estilo de esta aplicación…

Paso 1

Crea un nuevo proyecto en Android Studio con el nombre de “Styler” y añádele una actividad en blanco llamada “Main”.

Paso 2

Abre el archivo de diseño activity_main.xml y crea el siguiente diseño:

<resources>
 <!--Tema para el formulario-->
    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
        <!-- Estilos para Edit Texts-->
        <item name="android:editTextStyle">@style/EditTextStyle</item>
        <!--Estilos de ventana-->
        <item name="android:windowFullscreen">true</item>
    </style>

    <!--Estilos personalizados para los componentes del formulario-->
    <style name="Header" parent="@android:style/Widget.Holo.Light.TextView">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
        <item name="android:textColor">@android:color/holo_blue_bright</item>
        <item name="android:layout_marginTop">10dp</item>
    </style>

    <style name="Message" parent="@android:style/Widget.Holo.Light.TextView">
        <item name="android:textStyle">italic</item>
        <item name="android:textColor">@android:color/darker_gray</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

    <style name="Separator">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">1dp</item>
        <item name="android:background">@android:color/holo_blue_bright</item>
        <item name="android:layout_marginBottom">@dimen/activity_vertical_margin</item>
    </style>

    <style name="EditTextStyle" parent="@android:style/Widget.Holo.Light.EditText">
        <item name="android:background">@drawable/rectangle</item>
        <item name="android:padding">10dp</item>
    </style>

</resources>

Comprendamos cada estilo establecido:

AppTheme: Es el tema general de la aplicación y hereda sus atributos del tema Theme.Holo.Ligth.DarkActionBar. Atributos nuevos:

  • android:editTextStyle: Estilo visual de los Edit Texts. Aquó hicimos referencia al estilo EditTextStyle creado más abajo.
  • windowFullScreen: ¿Deseas que las actividades de la aplicación se ejecuten en pantalla completa?, elegimos true, ya que es un hecho.

Header: Representa una cabecera o título en nuestro formulario. Este hereda las características de un Text View Holo.Light. Atributos nuevos:

  • textAppearance: Tamaño de la fuente del view. Normalmente nos referiremos a tres tamaños: Small (Pequeño), Medium (Mediano) y Large (Grande).
  • layoutMarginTop: Se refiere a la margen superior del textview con respecto a los elementos dentro del layout.

Message: Este estilo representa el cuerpo de un mensaje dirigido al usuario. Hereda del mismo padre de Header. Atributos nuevos:

  • textStyle: Representa la modalidad de texto, cuyo valor puede ser italic, bold o normal.

Separator: Este elemento es un separador entre las secciones de nuestro layout. Representa una línea horizontal de 1dp de grosor y un largo ajustado al LinearLayout. Aunque parece un truco raro, es muy útil y sencillo para representar una línea flexible. Atributos nuevos:

  • background: Es el color, forma o imagen que un view tiene de fondo.
  • layout_marginBottom: Margen inferior de un view con respecto a un layout

EditTextStyle: Contiene el estilo de los edit texts de nuestro formulario. Atributos nuevos:

  • padding: Se refiere al espaciado que hay entre todas las margenes del view y su contenido.

Hago un paréntesis para señalar el recurso que hemos usado en el background de los edit texts. Se trata de una forma creada manualmente para representar el contenido del fondo.

Para ello se creó un nuevo recurso drawable llamado rectangle.xml con la siguiente descripción:

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:top="1dp" android:bottom="1dp">
        <shape
            android:shape="rectangle">

            <stroke
                android:width="1dp"
                android:color="@android:color/holo_blue_bright" />
            <solid android:color="#ffffffff" />

            <corners
                android:radius="10dp"/>

        </shape>
    </item>

</layer-list>

No entraremos en detalles sobre estos elementos, ya que es un tema de renderizado 2D con la API gráfica. Pero en resumen se puede observar que usamos un nodo <shape>, el cual representa una forma primitiva en el lienzo de dibujo.

Para este caso es un rectángulo, el cual tiene un recubrimiento (<stroke>) con nuestro azul predilecto y además un objeto <corner> que permite redondear las esquinas de nuestro rectángulo.

Paso 3

Ahora diseñaremos el layout de nuestra actividad Main con la siguiente descripción:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"

    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".Main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        style="@style/Header"
        android:text="@string/dataHeader"
        android:id="@+id/dataHeader"/>

    <View style="@style/Separator" />

    <EditText
        android:inputType="textPersonName"
        android:ems="10"
        android:id="@+id/nameField"
        android:layout_gravity="center_horizontal"
        android:hint="@string/nameField"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <EditText
        android:inputType="phone"
        android:ems="10"
        android:id="@+id/phoneField"
        android:layout_gravity="center_horizontal"
        android:hint="@string/phoneField"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

    <EditText
        android:inputType="textEmailAddress"
        android:ems="10"
        android:id="@+id/emailField"
        android:layout_gravity="center_horizontal"
        android:hint="@string/emailField"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:text="@string/optionsHeader"
        android:id="@+id/optionsHeader"
        style="@style/Header" />

    <View style="@style/Separator" />

    <TextView
        android:text="@string/newsletterText"
        android:id="@+id/newsletterText"
        android:layout_gravity="center_horizontal"
        style="@style/Message" />

    <CheckBox
        android:id="@+id/confirmBox"
        android:layout_gravity="center_horizontal"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" />

    <Button
        android:text="@string/sendButton"
        android:id="@+id/sendButton"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="41dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Como ves, hemos asignado al atributo style los estilos correspondientes. En los datos del suscriptor tenemos un textview con estilo de título y el texto “TUS DATOS”. Más abajo hay otro título donde añadimos las opciones adicionales relacionadas a la suscripción, este tiene el texto “OPCIONES”.

Las secciones están separadas por nuestros objetos Separators y el mensaje dirigido a nuestros usuarios tiene asignado el estilo Message.

Los Text Fields no tienen asignado ningún estilo, ya que su forma es heredada del tema de la aplicación.
Nota: No olvides añadir todos los textos representativos a tu archivo strings.xml. Te dejo las definiciones aquí abajo:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Styler</string>    
    <string name="action_settings">Settings</string>
    <string name="dataHeader">TUS DATOS</string>
    <string name="nameField">Nombre</string>
    <string name="phoneField">Teléfono</string>
    <string name="emailField">Email</string>
    <string name="optionsHeader">OPCIONES</string>
    <string name="newsletterText">¿Deseas recibir futuros articulos y promociones de Hermosa Programación?</string>
    <string name="sendButton">Enviar</string>

</resources>

Paso 4

Y por ultimo ejecutamos el proyecto para visualizar que se hayan aplicado el tema y los estilos particulares. En caso de que tu proyecto no tenga asignado el tema al elemento de la aplicación en el archivo AndroidManifest.xml, recuerda modificar el atributo theme:

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        <strong>android:theme="@style/AppTheme"</strong> >
        ...

Guardar

  • Luis Arevalo

    hola el codigo ya no esta disponible… lo puedes habilitar

  • Alvaro

    Buenas tardes,

    Lo primero agradecer un contenido de tanto valor y tan bien redactado; ya es la segunda vez que solicitándole a google una necesidad medianamente compleja(“android attr como modificarlo”) me aparece este blog.

    Como hice en el caso anterior comparto esta información por twitter para que le pueda servir de ayuda a mucha más gente. (@AlvaroIVM)

    Lo segundo tengo una pequeña duda, puedo configurar otro elemento style en el propio archivo styles.xml que se crea por defecto al crear un proyecto. Le pregunto esto ya que tengo ahora mismo este archivo de esta forma:


    @color/colorPrimary
    @color/colorPrimaryDark
    @color/colorAccent

    @color/colorHungry
    @color/colorThirsty

    y me da un error que por mi falta de experiencia no comprendo ya que se refiere al archivo attr y no conozco como acceder a este, el error es el siguiente:

    Error:(10, 5) No resource found that matches the given name: attr ‘colorThirsty’.

    cualquier ayuda o indicación sera de gran ayuda.

    Muchas gracias de antemano!

    Un saludo.

  • Jorge Najera

    Hola, tengo una duda, ¿como puedo hacer que sea el usuario quien escoge el tema de la aplicacion? Quiero decir, al presionar un botón la aplicación se convierte a un tono negro y al presionar otro que se convierta a un tema blanco

  • Miglior Dida

    hola no se si sea el lugar indicado. quisiera una ayuda para realizar un componente de intros para aplicaciones sin que el programador realiza ningun esfuerzo. eso conlleva a crear activitys,view y demas que son necesarios para una intro. EL PROBLEMA que tengo es que no se como llevar mi proyecto a que sea un componente,como lo es un boton que solo tenga q arrastrar y ya. si alguien me puede ayudar ,se lo agradeceria mucho asi sea alguna pauta

  • Daniel Enrique Rodriguez Caste

    Hola, quiero agradecerte por toda informacion, es muy util al momento de comenzar,

    y tengo una inquietud. quiero hacer mi propio Theme, y lo que quiero en el, es ocultar la barra la de NavigationBar, para eso hago que mi Theme herede de android:Theme.Panel
    esto me esconde las tres barras, (StatusBar, ActionBar y NavigationBar) pero resulta que despues no puedo hacer aparecer las otras dos barras que me interesan que son: StatusBar y ActionBar, tambien intente que mi Theme no herede de ningun Theme de Android, y hacer que se oculte la NavigationBar, no conozco la propuedad para ocultar solo la Barra de Navegación (NavigationBar).
    si saber como hacerlo te agradezco la ayuda

  • YIMY JOSUE HERCULES RUBIO

    Muy interesante tu post, pero me surge la duda de como hacer que sea una imagen animada la que se coloque de fondo.