La actividad (Activity) es la más común de las clases del SDK de Android para crear una pantalla en nuestra app. Dentro de cada actividad, colocaremos los diferentes componentes de la interfaz gráfica, como campos de introducción de texto, botones, etcétera. Toda actividad debe declararse en el manifiesto de nuestra app (AndroidManifest.xml), pues, de otro modo, obtendremos un error de compilación. Normalmente, además, crearemos un recurso layout que defina los elementos que componen la pantalla, así como su posición dentro de ella. De lo contrario, tendríamos que crear los componentes en tiempo de ejecución, lo que resulta más difícil y tendrá sentido solo en algunos casos particulares.
Como hemos mencionado, el archivo de layout definirá, mediante código XML, el aspecto y los componentes de la interfaz gráfica de la actividad. Existen diferentes tipos de layouts predefinidos, que nos ayudarán a ordenar los componentes de diferentes formas según nuestras necesidades. Además, estos contenedores pueden agruparse jerárquicamente unos sobre otros, con la intención de crear interfaces gráficas más complejas.
Es conveniente, no obstante, utilizar lo menos posible este mecanismo, pues la eficiencia de la interfaz gráfica puede verse reducida. Veamos algunos de los layouts más conocidos:
LinearLayout
Uno de los más sencillos y, a la vez, más usados. Este contenedor agrupa las vistas en su interior de forma lineal, en dirección horizontal o vertical, dependiendo del parámetro orientation. Veamos un ejemplo:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="EditText 1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="EditText 2" />
<EditText
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:hint="EditText 3" />
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Button 1" />
</LinearLayout>
El elemento raíz es un LinearLayout, y la etiqueta orientation indica que los elementos se ordenarán verticalmente.
Observa cómo todos los elementos presentan los atributos layout_width y layout_height. Estos atributos son obligatorios en todos los tipos de layout, e indican el ancho y el alto de cada componente, es decir, cuánto espacio ocupa cada ventana dentro del contenedor. Estos valores pueden ser valores fijos, como 16px (para píxeles), 16dp (siendo dp una medida estándar, un píxel virtual que se adaptará a cada densidad de pantalla), etcétera. Estos valores pueden ser también valores clave, como match_parent (utiliza todo el espacio que ofrece el contenedor padre) o wrap_content (utiliza solo el espacio que necesite el contenido de la ventana, por ejemplo, un botón ocupará lo que ocupe su título, y no más).
Observa que en el último EditText se ha utilizado layout_height=0dp; esto no significa que tenga altura cero, sino que pretendemos que la vista se extienda todo el espacio sobrante que han dejado el resto de componentes. En la pestaña Design se puede ver el resultado del layout que se acaba de codificar:
RelativeLayout
Este contenedor agrupa a las vistas en una posición relativa al layout contenedor o entre las distintas vistas que agrupa. Comenzar a situar los elementos en cualquiera de los cuatro lados del contenedor y permite ir añadiendo nuevos elementos pegados a estos.
<RelativeLayout
xmlns:android="http://schemas...
android:layout_height="match_parent"
android:layout_width="match_parent">
<AnalogClock
android:id="@+id/AnalogClock01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<CheckBox
android:id="@+id/CheckBox01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/AnalogClock01"
android:text="Un checkBox"/>
<Button
android:id="@+id/Button01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Un botón"
android:layout_below="@id/CheckBox01"/>
<TextView
android:id="@+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Un texto cualquiera"/>
</RelativeLayout>
TableLayout
Contenedor tipo tabla que utiliza filas y columnas para alinear los elementos en la vista. Las columnas y filas pueden tener un tamaño particular o ampliarse, y las celdas pueden extenderse más allá de sus límites. Observa el parámetro weigth el cual asigna un valor de importancia con respecto al espacio que ocupa. El valor por defecto es 0.
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableRow>
<AnalogClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="10" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Un checkBox" />
</TableRow>
<TableRow>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="10"
android:text="Un botón" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Un texto cualquiera" />
</TableRow>
</TableLayout>
GridLayout
Muy parecido al TableLayout, en el que el diseño se basa en una rejilla de celdas de diferentes tamaños.
ConstraintLayout
El layout más utilizado actualmente mejorando al RelativeLayout. Antes de la aparición del ConstraintLayout, construir una interfaz gráfica compleja requería de la composición jerárquica de varios, a veces demasiados, layouts unos dentro de otros para obtener el orden y la colocación precisos de las ventanas en su interior. El problema de ese tipo de anidamiento es que llega un punto en el que la eficiencia del layout comienza a degradarse, la presentación de la interfaz gráfica se ralentiza y el consumo de memoria se dispara. Por ello, los desarrolladores de Android crearon el ConstraintLayout. Gracias a la versatilidad de este contenedor, raramente será necesario encadenarlo a otro contenedor, pues permite ordenar los componentes de forma eficiente y elástica. Tras su aparición, los demás layouts han quedado obsoletos. Además, este layout permite el diseño de forma gráfica mediante cajitas con enlaces laterales que pueden asociarse con el contenedor padre o entre las vistas. Ese diseño se traduce en código con los atributos de control de posición:
- layout_constraintLeft_toLeftOf o toRightOf: la vista se alineará a la izquierda de la parte izquierda o derecha del componente que se indique. El elemento al que hace referencia se indicará mediante el id o con la palabra claveparent, que indica que la posición es relativa al contenedor padre.
- layout_constraintRight_toLeftOf o toRightOf: la vista se alineará a la derecha de la parte izquierda o derecha del componente que se indique.
- layout_constraintTop_toTopOf o toBottomOf: la vista se alineará en lo alto de la parte superior o inferior del componente que se indique.
- layout_constraintBottom_toTopOf o toBottomOf: la vista se alineará debajo de la parte superior o inferior del componente que se indique.
Tiene otras opciones para establecer márgenes, centrado, offsets, etcétera. Lo mejor para comprobar todas las posibilidades de este layout es jugar con la herramienta Design, cambiando las configuraciones de las vistas y observando cómo cada parámetro afecta al diseño final de la interfaz gráfica.