Saltar la navegación

3.2.1. Activity y Layout

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.

Tipos de Actividades

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:

Imagen resultado Layout

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>

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>

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.

Dentro de cada contenedor layout podremos colocar nuestras vistas, que son los componentes visuales que el usuario puede ver y con los que puede interactuar. Ya hemos visto algunos, pero hagamos una lista de los más usados:

TextView

Representa un texto estático para el usuario, aunque podemos cambiar su texto desde código. Puede servirnos para presentar información al usuario, como mensajes o etiquetas de otros componentes.

EditText

Representa un campo de texto que el usuario puede rellenar. Gracias a sus atributos, podemos crear un filtro de entrada, de modo que si, por ejemplo, solo queremos números, el campo solo acepte números, etcétera.

Button

Un componente que el usuario puede presionar para obtener alguna función. Estableceremos un listener o el atributo onClick para definir las acciones que efectuar cuando sea pulsado.

ImageButton

Un botón exactamente igual al anterior, con la diferencia de que podemos añadirle un icono para un mejor aspecto visual de su función.

ImageView

Representa una imagen estática, aunque podemos cambiarla dinámicamente mediante el código. Puede servirnos para mejorar el aspecto de la interfaz gráfica o para presentar una imagen real relacionada con datos.

RecyclerView

Una lista de objetos cuya presentación podemos adaptar a nuestras necesidades mediante un adapter. Este tipo de listas son muy eficientes, pues solo retienen en memoria los objetos que serán mostrados.

Switch

Representa un interruptor, puede estar en on o en off. Puede servirnos para presentar al usuario dos opciones posibles de las que debe escoger una.

Checkbox

Representa una opción seleccionable. Sería parecido al anterior, mostrando si una opción está activa o no.

RadioButton + RadioGroup

Similar al anterior, con la diferencia de que estas opciones son excluyentes: si eliges una opción, las demás se desactivarán.

Layout por defectoComo observamos en el código autogenerado, nuestra actividad MainActivity hereda de AppCompatActivity de modo que podamos aprovechar las funcionalidades básicas sin
más código. La función onCreate debe ser sobreescrita para especificar el layout que deseamos para nuestra ventana. Pulsar la tecla Ctrl mientras hacemos clic sobre activity_main, navegaremos al editor de layouts, que nos mostrará el diseños de la ventana MainActivity (ver imagen).

Los layouts se definen con código XML, pero no debemos alarmarnos antes de tiempo, pues no tendremos que recordar todos y cada uno de los parámetros. Para facilitarnos el trabajo, el editor de layouts dispone de capacidades gráficas con las que podremos añadir, eliminar y distribuir los componentes de nuestra interfaz gráfica sin necesidad de escribir código XML. Sí es cierto que, en ocasiones, nos será más sencillo modificar directamente el código, por eso es conveniente ir comprendiendo cada etiqueta XML.

Por ejemplo, la segunda línea de la imagen indica que el layout será un ConstraintLayout, que es uno de los más utilizados actualmente. Dentro del layout encontramos un TextView, que no es más que un texto que el usuario verá pero no podrá editar.

Ejemplo

Haz clic tras TextView, pulsa Intro y añade la línea: android:id="@+id/tvSaludo". Se ha establecido un indicador para el componente de modo que se pueda acceder a él desde el código. Ahora observa que en la esquina superior derecha del editor existen tres opciones:

  • Code, muestra el código XML del layout;
  • Split, muestra tanto el código como el diseño visual; 
  • Design, muestra únicamente el diseño gráfico de la ventana.

Selecciona Design. Aparecerá un mockup de cómo se verá la actividad. En el lateral izquierdo aparece un listado de componentes gráficos, que se puede arrastrar hasta la ventana de diseño, para añadirlos al layout.

En el lateral derecho se encuentran los atributos del componente actualmente seleccionado.

Añade un componente Button al layout: para disponerlo en un ConstraintLayout, tendremos que hacer clic en cada uno de los circulitos y arrastrar hasta los bordes de la ventana para dejarlo anclado. La bolita superior podemos anclarla a la parte baja del TextView que ya teníamos:

Ejemplo Layout

Es importante establecer un id en el botón para poder acceder a él desde el código:

android:id="@+id/tvSaludo"

El acceso al elemento del layout se haría indicando el id anterior en el MainActivity:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val btnCambiarSaludo: Button? = findViewById(R.id.btnCambiarSaludo)
        val tvSaludo: TextView? = findViewById(R.id.tvSaludo)
        btnCambiarSaludo?.setOnClickListener {
            tvSaludo?.text="Hola a tod@s"
        }
    }
}

FrameLayout

Este tipo de ViewGroup, posiciona las vistas usando todo el contenedor, sin distribuirlas espacialmente. Este Layout suele utilizarse cuando queremos que varias vistas ocupen un mismo lugar. Podemos hacer que sólo una sea visible, o superponerlas.Para modificar la visibilidad de un elemento utilizaremos la propiedad visibility y, para posicionarlas, la propiedad layout_gravity.

Si deseamos indicar varias posiciones de gravedad, las separaremos con el símbolo | como en el ejemplo siguiente:

android:layout_gravity="bottom|end"

De esta forma, el objeto "caerá" hasta la parte inferior de la pantalla y a la derecha.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|center">
        <AnalogClock
            android:layout_width="100pt"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|center"
            android:text="Un texto cualquiera" />
    </FrameLayout>
    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Un checkBox" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:text="Un botón" />
</FrameLayout>

FrameLayout

Creado con eXeLearning (Ventana nueva)