Autor

Alejandro Alcalde

Data Scientist and Computer Scientist. Creator of this blog.

Más artículos de Alejandro Alcalde | Porfolio

Éste artículo es una traducción del blog de Cyril Mottier, al cual le agradezco que me diera permiso para escribirlo. Quizás te interese leer (Pon a dieta tus APKs), otra traducción de su blog.

La mayoría de interfaces de usuario (en móviles o web) se basan en el concepto de rejillas (Grids a partir de ahora). Los Grids consisten básicamente en separar la interfaz de usuario en una serie de cuadrados alineados que pueden ser fusionados para crear bloques. Usando el principio Grid en el desarrollo de la UI (Interfaz de usuario) ayuda a alinear elementos, trae consistencia, genera un código limpio, asegura que el usuario pueda analizar fácilmente el contenido de la interfaz etc. En resumen, los Grids son una herramienta de diseño extremadamante potentes.

El principio Grid

Usar el principio Grid, requiere generalmente que el desarrollador añada algún margen/paddin/espacio extra entre elementos. En efecto, añadir espacio entre elementos ayuda a mantener una separación clara entre bloques mientras se conserva un gran nivel del legibilidad en la interfaz. Todos los desarrolladores Android están familiarizados con éstos conceptos, y en la mayoría de los casos se solucionan usando características del framework como padding y/o margin en las Views. Para aislar claramente la lógica del programa de la interfaz, generalmente ésto se hace en los ficheros XML que definen la interfaz. Si bien éste método funciona cuando la interfaz es estática, puede se complicado para interfaces dinámicas en las cuales hay elementos que se muestran o desaparecen según sea necesario. Éste artículo pretende dar algunos consejos para manejar correctamente interfaces dinámicas basadas en Grids.

Ejemplo

Creemos un layout simple a modo de ejemplo. Consiste en una barra horizontal de tres Buttons que aparecen debajo de una View estática (El logo de la aplicación, por ejemplo). El resultado es el siguiente:

layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  android:padding="@dimen/spacing_medium">

  <TextView
    android:layout_width="match_parent"
    android:layout_height="128dp"
    android:background="@color/light_gray"
    android:gravity="center"
    android:text="@string/application_logo"
    android:textAppearance="@android:style/TextAppearance.Material.Display1" />

  <LinearLayout
    android:id="@+id/buttons_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
      android:id="@+id/btn_first"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:background="@drawable/purple"
      android:text="@string/button_1" />

    <Button
      android:id="@+id/btn_second"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:background="@drawable/indigo"
      android:text="@string/button_2" />

    <Button
      android:id="@+id/btn_third"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_weight="1"
      android:background="@drawable/teal"
      android:text="@string/button_3" />

  </LinearLayout>

</LinearLayout>

La interfaz mostrada en la imagen de arriba depende claramente en la idea de un Grid. Sin embargo, carece de espacio entre elementos que permitan al usuario distinguir claramente la entidades independientes de la interfaz. Corrijamos éste problema añadiendo android:layout_marginTop="@dimen/spacing_medium" al LinearLayout identificado por @id/buttons_container y android:layout_marginRight="@dimen/spacing_medium" a los botones @id/btn_first y @id/btn_second:

El problema de la interfaz dinámica

La interfaz de arriba tiene un aspecto bastante bueno: Buena apariencia, es legible, etc. Desafortunadamente, las cosas se ponen un poco mal cuando se ocultan dinámicamente algunas Views en el layout. De hecho, imaginemos que la función que se activaría con un click en el botón @id/btn_third requiere de alguna característica no disponible en el dispositivo (Google Play Services por ejemplo). La mejor forma de no desordenar la interfaz es ocultar el tercer botón con View.GONE:

Como es de esperar, el botón @id/btn_third desaparece, pero el borde derecho de @id/btn_second no está alineado con el borde derecho del icono de la aplicación. La razón principal de éste problema se debe a que la técnica usando el margen funciona bien siempre que se mantenga la asunción hecha al principio: cada View con un margen derecho/superior tiene una View vecina a su derecha/arriba. Ocultar algunas Views en la barra va en contra de esta restricción.

Usar un separador para resolver el problema

Un truco obvio para resolver éste problema podría ser cambiar manualmente el margen de los elementos en Java. Lo cual es una pésima solución. Otra alternativa sería usar un Layout que gestione automáticamente los espacios entre elementos. GridLayout es uno de ellos. Por desgracia, éste Layout es engorroso de usar y no permite especificar un margen concreto entre elementos (Solo está disponible el margen por defecto).

En realidad, LinearLayout gestiona la idea del espacio entre elementos. Ésta característica es algo desconocida ya que está bastante escondida en el framework pero funciona como si de magia se tratara. El truco consiste en usar un Drawable con anchura/altura intrínsicos como separador de elementos del LinearLayout:

drawable/spacer_medium.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">

  <size
    android:width="@dimen/spacing_medium"
    android:height="@dimen/spacing_medium" />

    <solid android:color="@android:color/transparent" />

  </shape>

Ahora se puede usar el Drawable creado como un separador entre elementos estableciéndolo como el separador del LinearLayout:

layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:divider="@drawable/spacer_medium"
  android:orientation="vertical"
  android:padding="@dimen/spacing_medium"
  android:showDividers="middle">

  <!-- TextView -->

  <LinearLayout
    android:id="@+id/buttons_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:divider="@drawable/spacer_medium"
    android:orientation="horizontal"
    android:showDividers="middle">

    <!-- Buttons -->

  </LinearLayout>

</LinearLayout>

Conclusión

El framework de Android contiene unas cuantas características que pueden usarse y modificar para cumplir con una tarea diferente a la esperada. La idea de un Drawable forma parte de dichos trucos habitualmente. Asegúrate de conocer plenamente el concepto de Drawable, ya que puede ayudarte a simplificar el código en más de una ocasión.

Referencias

¿Has visto algún error?: Por favor, ayúdame a corregirlo contactando conmigo o comentando abajo.

Categorías: