La columna 80

El blog técnico-personal de Ángel J. Vico… en español

Diseños Android básicos: FrameLayout

Posted by Ángel J. Vico en 22 de agosto de 2012

Llevo ya unos cuantos posts dedicados a la interfaz de usuario en Android. Empecé hablando de las actividades y su ciclo de vida, y continué con varios posts sobre las vistas, la forma en que se organizan en diseños y cómo se muestran esos diseños en las actividades. También hemos visto ya los dos tipos principales de vistas que tenemos, diseños y widgets e incluso he enumerado algunos de los más usuales, incluyendo una breve descripción de su cometido.

Es el momento ahora de profundizar más en esas vistas, viendo más detalles sobre ellas y ejemplos de uso. Empezaremos por los diseños básicos, dado que será lo primero que tengamos que crear en nuestra actividad, para subdividir el espacio y controlar la ubicación de los widgets. En concreto, comenzaremos por el FrameLayout, el diseño más sencillo de todos los disponibles, pero también el más eficiente.

FrameLayout no realiza ninguna distribución de las vistas, simplemente las coloca unas encima de otras. Esto le evita tener que relacionar los tamaños de unas vistas con los de las demás, por lo que se ahorra recorridos del árbol de vistas, tardando menos en mostrar su contenido.

La gravedad

Que FrameLayout coloque las vistas una sobre otra no significa que todas se alineen automáticamente a la esquina superior izquierda del diseño. Por un lado tenemos el padding. El diseño, al ser una vista, también tiene esa propiedad. Y por otro lado tenemos el margen, si el FrameLayout está contenido en otro diseño que lo soporta. Puedes ver más detalles sobre padding y margen en este post.

Pero, además de todo esto, tenemos un parámetro que nos permite controlar el alineamiento de las vistas contenidas en el diseño: la gravedad. Este parámetro, definido en FrameLayout.LayoutParams, y que se corresponde con el atributo android:layout_gravity no es exclusivo de FrameLayout. LinearLayout también lo proporciona y, por herencia, también TableLayout, TableRow e incluso RadioGroup. Los valores disponibles para el parámetro y el resultado obtenido con cada uno de ellos son comunes para todos estos diseños, por lo que les será de aplicación lo que voy a explicar a continuación.

La gravedad permite indicar cómo se debe alinear la vista sobre la que se aplica, tanto horizontal como verticalmente, en relación a los límites del área disponible para el contenido del FrameLayout. Este área incluye todo el espacio que el FrameLayout ocupa en la actividad menos el padding que se haya establecido.

En la siguiente lista se enumeran algunos de los valores que se pueden utilizar para establecer la gravedad. En el archivo XML, al atributo android:layout_gravity se le asigna una cadena de texto que contiene uno o más de estos valores. Si hay más de uno se separan mediante |. Para cada uno de estos valores existe una constante de igual nombre que se puede utilizar para asignar la gravedad mediante código Java. De forma similar, si en Java usa más de una constante, se agregan mediante el operador lógico |:

  • top y bottom: alinean el borde superior/inferior de la vista con el del área útil del diseño, sin alterar el tamaño de la vista.

  • left y right: alinean el borde izquierdo/derecho de la vista con el del área útil del diseño, sin alterar el tamaño de la vista.

  • center_horizontal y center_vertical: centran la vista horizontal o verticalmente en el área útil del diseño sin alterar su tamaño.

  • center: centra la vista vertical y horizontalmente, de forma simultánea, en el área útil del diseño sin alterar su tamaño.

En el siguiente ejemplo podemos ver el funcionamiento de las primeras constantes enumeradas:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent">
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Sin gravedad"
      android:textSize="23sp"
      android:background="#080" />
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="right"
      android:background="#080"
      android:textSize="23sp"
      android:layout_gravity="right" />
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="bottom"
      android:background="#080"
      android:textSize="23sp"
      android:layout_gravity="bottom" />
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="bottom|right"
      android:background="#080"
      android:textSize="23sp"
      android:layout_gravity="bottom|right" />
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="center_vertical"
      android:background="#080"
      android:textSize="23sp"
      android:layout_gravity="center_vertical" />
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="center_horizontal"
      android:background="#080"
      android:textSize="23sp"
      android:layout_gravity="center_horizontal" />
</FrameLayout>

Este ejemplo genera la siguiente interfaz de usuario:

Usos básicos de la gravedad

La gravedad puede tomar más valores que los descritos aquí, pero su funcionamiento es algo más complejo, por lo que los trataré con detalle en un futuro post.

Crear FrameLayout por código

Ya hemos visto en el ejemplo de uso del parámetro gravedad cómo se utiliza el diseño FrameLayout en XML. Veamos ahora cómo crear esa misma interfaz de usuario por código:

   @Override
   public void onCreate (Bundle savedInstanceState)
   {
      super.onCreate(savedInstanceState);

      TextView tv1 = new TextView(this);
      tv1.setLayoutParams(new ViewGroup.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT));
      tv1.setText("Sin gravedad");
      tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv1.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv2 = new TextView(this);
      tv2.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.RIGHT));
      tv2.setText("right");
      tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv2.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv3 = new TextView(this);
      tv3.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.BOTTOM));
      tv3.setText("bottom");
      tv3.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv3.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv4 = new TextView(this);
      tv4.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.BOTTOM | Gravity.RIGHT));
      tv4.setText("bottom|right");
      tv4.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv4.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv5 = new TextView(this);
      tv5.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.CENTER_VERTICAL));
      tv5.setText("center_vertical");
      tv5.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv5.setBackgroundColor(Color.rgb(0, 136, 0));

      TextView tv6 = new TextView(this);
      tv6.setLayoutParams(new FrameLayout.LayoutParams(
         ViewGroup.LayoutParams.WRAP_CONTENT,
         ViewGroup.LayoutParams.WRAP_CONTENT,
         Gravity.CENTER_HORIZONTAL));
      tv6.setText("center_horizontal");
      tv6.setTextSize(TypedValue.COMPLEX_UNIT_SP, 23);
      tv6.setBackgroundColor(Color.rgb(0, 136, 0));

      FrameLayout fl = new FrameLayout(this);
      fl.addView(tv1);
      fl.addView(tv2);
      fl.addView(tv3);
      fl.addView(tv4);
      fl.addView(tv5);
      fl.addView(tv6);

      setContentView(fl);
   }

En el código se observa cómo se crean primero los TextView y luego el FrameLayout. Los TextView se añaden al FrameLayout y después se asigna el diseño a la actividad para que se muestre. Se puede observar también cómo la gravedad se asigna a cada widget como parámetro, creando un FrameLayout.LayoutParams y pasándosela al constructor. Además, no es necesario asignar las constantes fill_parent a los atributos correspondientes del FrameLayout porque ese es el valor que tienen de forma predeterminada.

Conviene aclarar que los valores 0, 136 y 0 que se le pasan al método rgb de la clase Color, son los equivalentes decimales a la cadena hexadecimal que hemos utilizado en el archivo XML: #080. La conversión no es directa porque en XML hemos usado el formato #RGB, que sólo emplea un dígito hexadecimal para cada color. En este caso, los valores posibles para cada color oscilan entre 0 y 15. Sin embargo, los valores que admite el método rgb oscilan entre 0 y 255, por lo que la conversión se ha tenido que hacer de forma proporcional.

Finalmente, comentar que la clase TextView dispone de un método setTextSize que permite especificar una dimensión junto con sus unidades para establecer el tamaño del texto. De esta forma nos ahorramos tener que calcular primero los píxeles equivalentes utilizando los métodos que vimos en el post dedicado a las dimensiones.

En el próximo post veremos algunas especializaciones del FrameLayout: clases que heredan de este diseño, incorporando su funcionalidad básica y añadiendo funcionalidad particular.

Recuerda que en esta página dispones de enlaces a todos los artículos sobre Android que he publicado en La columna 80.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s