Inicio Android Interfaz de usuario en Android: Layouts

Interfaz de usuario en Android: Layouts

por sgoliver

Actualizado: Abril 2020

En el artículo anterior del curso, donde desarrollamos una sencilla aplicación Android desde cero, ya hicimos algunos comentarios sobre los layouts. Como ya indicamos, los layouts son elementos no visuales destinados a controlar la distribución, posición y dimensiones de los controles que se insertan en su interior. Estos componentes extienden a la clase base ViewGroup, como muchos otros componentes contenedores, es decir, capaces de contener a otros controles. En el post anterior conocimos la existencia de un tipo concreto de layout, LinearLayout, aunque Android nos proporciona algunos otros. Veámos cuántos y cuáles.

FrameLayout

Éste es el más simple de todos los layouts de Android. Un FrameLayout coloca todos sus controles hijos alineados con su esquina superior izquierda, de forma que cada control quedará oculto por el control siguiente (a menos que éste último tenga transparencia). Por ello, suele utilizarse para mostrar un único control en su interior, a modo de contenedor (placeholder) sencillo para un sólo elemento sustituible, por ejemplo una imagen.

Los componentes incluidos en un FrameLayout podrán establecer sus propiedades android:layout_width y android:layout_height, que podrán tomar los valores «match_parent» (para que el control hijo tome la dimensión de su layout contenedor) o «wrap_content» (para que el control hijo tome la dimensión de su contenido). 

Veamos un ejemplo donde colocamos un FrameLayout que ocupará toda la pantalla (estableciendo como «match_parent» tanto su ancho como su alto) y en su interior un botón (Button) con el ancho ajustado a su contenedor («match_parent«) y el alto a su contenido («wrap_content«):

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button android:id="@+id/txtBoton1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Botón 1" />

</FrameLayout>

Con el código anterior conseguimos un layout tan sencillo como el siguiente:

LinearLayout

El siguiente tipo de layout en cuanto a nivel de complejidad es el LinearLayout. Este layout apila uno tras otro todos sus elementos hijos en sentido horizontal o vertical según se establezca su propiedad android:orientation.

Al igual que en un FrameLayout, los elementos contenidos en un LinearLayout pueden establecer sus propiedades android:layout_width y android:layout_height para determinar sus dimensiones dentro del layout.

Veamos un ejemplo donde colocamos dos botones dentro de un LinearLayout con orientación vertical:

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

    <Button android:id="@+id/txtBoton1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Botón 1" />

    <Button android:id="@+id/txtBoton2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Botón 2" />

</LinearLayout>

El layout anterior quedaría de la siguiente forma:

Pero en el caso de un LinearLayout, tendremos otro parámetro con el que jugar, la propiedad android:layout_weight. Esta propiedad nos va a permitir dar a los elementos contenidos en el layout unas dimensiones proporcionales entre ellas. Esto es más difícil de explicar que de comprender con un ejemplo. Si incluimos en un LinearLayout vertical dos botones (Button) y a uno de ellos le establecemos un layout_weight="1" y al otro un layout_weight="2" conseguiremos como efecto que toda la superficie del layout quede ocupada por los dos botones y que además el segundo sea el doble (relación entre sus propiedades weight) de alto que el primero.

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

    <Button android:id="@+id/txtBoton1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Botón 1" />

    <Button android:id="@+id/txtBoton2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:text="Botón 2" />

</LinearLayout>

Con el código anterior conseguiríamos un layout como el siguiente:

Así pues, a pesar de la simplicidad aparente de este layout resulta ser lo suficiente versátil como para sernos de utilidad en muchas ocasiones.

TableLayout

Un TableLayout permite distribuir sus elementos hijos de forma tabular, definiendo las filas y columnas necesarias, y la posición de cada componente dentro de la tabla.

La estructura de la tabla se define de forma similar a como se hace en HTML, es decir, indicando las filas que compondrán la tabla (objetos TableRow), y dentro de cada fila las columnas necesarias, con la salvedad de que no existe ningún objeto especial para definir una columna (algo así como un TableColumn) sino que directamente insertaremos los controles necesarios dentro del TableRow y cada componente insertado (que puede ser un control sencillo o incluso otro ViewGroup) corresponderá a una columna de la tabla. De esta forma, el número final de filas de la tabla se corresponderá con el número de elementos TableRow insertados, y el número total de columnas quedará determinado por el número de componentes de la fila que más componentes contenga.

Por norma general, el ancho de cada columna se corresponderá con el ancho del mayor componente de dicha columna, pero existen una serie de propiedades que nos ayudarán a modificar este comportamiento:

  • android:stretchColumns. Indicará las columnas que pueden expandir para absorber el espacio libre dejado por las demás columnas a la derecha de la pantalla.
  • android:shrinkColumns. Indicará las columnas que se pueden contraer para dejar espacio al resto de columnas que se puedan salir por la derecha de la pantalla.
  • android:collapseColumns. Indicará las columnas de la tabla que se quieren ocultar completamente.

Todas estas propiedades del TableLayout pueden recibir una lista de índices de columnas separados por comas (ejemplo: android:stretchColumns="1,2,3") o un asterisco para indicar que debe aplicar a todas las columnas (ejemplo: android:stretchColumns="*").

Otra característica importante es la posibilidad de que una celda determinada pueda ocupar el espacio de varias columnas de la tabla (análogo al atributo colspan de HTML). Esto se indicará mediante la propiedad android:layout_span del componente concreto que deberá tomar dicho espacio.

Veamos un ejemplo con varios de estos elementos:

<TableLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:stretchColumns="0,1,2">

    <TableRow>
        <TextView android:text="Celda 1.1" />
        <TextView android:text="Celda 1.2" />
        <TextView android:text="Celda 1.3" />
    </TableRow>

    <TableRow>
        <TextView android:text="Celda 2.1" />
        <TextView android:text="Celda 2.2" />
        <TextView android:text="Celda 2.3" />
    </TableRow>

    <TableRow>
        <TextView android:text="Celda doble de ancho 3.1"
            android:layout_span="2" />
        <TextView android:text="Celda 3.2" />
    </TableRow>
</TableLayout>

El layout resultante del código anterior sería el siguiente:

GridLayout

Sus características son similares al TableLayout, ya que se utiliza igualmente para distribuir los diferentes elementos de la interfaz de forma tabular, distribuidos en filas y columnas. La diferencia entre ellos estriba en la forma que tiene el GridLayout de colocar y distribuir sus elementos hijos en el espacio disponible. En este caso, a diferencia del TableLayout indicaremos el número de filas y columnas como propiedades del layout, mediante android:rowCount y android:columnCount. Con estos datos ya no es necesario ningún tipo de elemento para indicar las filas, como hacíamos con el elemento TableRow del TableLayout, sino que los diferentes elementos hijos se irán colocando ordenadamente por filas o columnas (dependiendo de la propiedad android:orientation) hasta completar el número de filas o columnas indicadas en los atributos anteriores. Adicionalmente, igual que en el caso anterior, también tendremos disponibles las propiedades android:layout_rowSpan y android:layout_columnSpan para conseguir que una celda ocupe el lugar de varias filas o columnas. Por su parte, para definir cómo ocupar el espacio horizontal disponible ocupado por las columnas debemos jugar con la propiedad layout_columnWeight de cada elemento hijo.

Existe también una forma de indicar de forma explícita la fila y columna que debe ocupar un determinado elemento hijo contenido en el GridLayout, y se consigue utilizando los atributos android:layout_row y android:layout_column. De cualquier forma, salvo para configuraciones complejas del grid no suele ser necesario utilizar estas propiedades.

Con todo esto en cuenta, para conseguir una distribución equivalente a la del ejemplo anterior del TableLayout, necesitaríamos escribir un código como el siguiente:

<GridLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:rowCount="2"
    android:columnCount="3"
    android:orientation="horizontal">

    <TextView android:layout_columnWeight="1" android:text="Celda 1.1" />
    <TextView android:layout_columnWeight="1" android:text="Celda 1.2" />
    <TextView android:layout_columnWeight="1" android:text="Celda 1.3" />

    <TextView android:layout_columnWeight="1" android:text="Celda 2.1" />
    <TextView android:layout_columnWeight="1" android:text="Celda 2.2" />
    <TextView android:layout_columnWeight="1" android:text="Celda 2.3" />

    <TextView android:layout_columnWeight="1" android:text="Celda doble de ancho 3.1"
        android:layout_columnSpan="2" />
    <TextView android:layout_columnWeight="1" android:text="Celda 3.2" />

</GridLayout>

RelativeLayout

El último tipo de layout que vamos a ver es el RelativeLayout. Este layout permite especificar la posición de cada elemento de forma relativa a su elemento padre o a cualquier otro elemento incluido en el propio layout. De esta forma, al incluir un nuevo elemento X podremos indicar por ejemplo que debe colocarse debajo del elemento Y y alineado a la derecha del layout padre. Veamos esto en el ejemplo siguiente:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText android:id="@+id/txtNombre"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text" />

    <Button android:id="@+id/btnAceptar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/txtNombre"
        android:layout_alignParentRight="true"
        android:text="Aceptar" />
  
</RelativeLayout>

En el ejemplo, el botón (Button) se colocará debajo del cuadro de texto (EditText) dado que se ha establecido la propiedad android:layout_below="@id/txtNombre" y alineado a la derecha del layout padre al establecer android:layout_alignParentRight="true", Quedaría algo así:

Al igual que estas tres propiedades, en un RelativeLayout tendremos un sinfín de propiedades para colocar cada control justo donde queramos. Veamos las principales [creo que sus propios nombres explican perfectamente la función de cada una]:

Posición relativa a otro control:

  • android:layout_above
  • android:layout_below
  • android:layout_toLeftOf
  • android:layout_toRightOf
  • android:layout_alignLeft
  • android:layout_alignRight
  • android:layout_alignTop
  • android:layout_alignBottom
  • android:layout_alignBaseline

Posición relativa al layout padre:

  • android:layout_alignParentLeft
  • android:layout_alignParentRight
  • android:layout_alignParentTop
  • android:layout_alignParentBottom
  • android:layout_centerHorizontal
  • android:layout_centerVertical
  • android:layout_centerInParent

Por último indicar que cualquiera de los tipos de layout anteriores poseen otras propiedades comunes como por ejemplo los márgenes exteriores (margin) e interiores (padding) que pueden establecerse mediante los siguientes atributos:

Opciones de margen exterior:

  • android:layout_margin
  • android:layout_marginBottom
  • android:layout_marginTop
  • android:layout_marginLeft
  • android:layout_marginRight

Opciones de margen interior:

  • android:padding
  • android:paddingBottom
  • android:paddingTop
  • android:paddingLeft
  • android:paddingRight

ConstraintLayout

Aunque lo he dejado para el final porque no es el tipo de layout que más me interesa para este curso, no podía faltar en esta entrada ya que actualmente es el layout recomendado por Google para definir cualquier interfaz de cierta complejidad. Aunque con los tipos de layout descritos hasta este momento en esta entrada podríamos definir casi cualquier interfaz, habitualmente anidando unos dentro de otros, el nuevo ConstraintLayout tiene la ventaja de ser capaz de conseguir los mismos resultados sin necesidad de anidar diferentes layouts, es decir, con un árbol o jerarquía de componentes mucho más «plana», y por tanto más eficiente.

¿Y por qué digo entonces que no me interesa para este curso? Pues básicamente porque es un layout pensado especialmente para ser utilizado mediante el editor gráfico de Android Studio (vista de diseño), y no tanto mediante la edición directa de su código XML (vista de código). En este curso prefiero centrar esfuerzos en comprender qué ocurre en cada uno de los componente de nuestras aplicaciones, incluida la interfaz aunque nos conformemos con interfaces más sencillas, y el código generado por ConstraintLayout no permite hacer esto con facilidad. Aunque nada nos impide ver y editar el XML de este tipo de layouts es algo que no recomiendo a nadie, ya que dependiendo de la complejidad de la interfaz puede llegar a ser bastante impracticable. Si quieres utilizar un layout de este tipo deberías usar casi siempre la vista de diseño de layouts, tipo drag and drop, y dejar que Android Studio gestione el código XML de fondo.

En principio, en este curso no voy a dedicar más tiempo al ConstraintLayout, aunque por supuesto sí os invito a conocerlo. Si estáis interesados en saber más sobre él Google proporciona mucha información en su web de desarrolladores, por ejemplo en los enlaces siguientes:

Y por ahora dejamos aquí el tema de los layouts. Más adelante en el curso veremos otros elementos que, a pesar de nos ser layouts puros como los que hemos visto en esta entrada, también extienden de ViewGroup, como por ejemplo las vistas de tipo lista o tabla/grid (RecyclerView) o las pestañas/tabs (TabLayout), y otros componentes algo más complejos como el CoordinatorLayout.

También te puede interesar

48 comentarios

Interfaz de usuario en Android: Controles básicos (I) | sgoliver.net blog 19/08/2010 - 9:45

[…] el artículo anterior ya vimos los distintos tipos de layouts con los que contamos en Android para distribuir los […]

Responder
Desarrollo en Android | sgoliver.net blog 07/09/2010 - 0:45

[…] Interfaz de usuario en Android: Layouts […]

Responder
jesus 01/02/2011 - 20:32

Hola, excelente tus articulos, me han servido de mucho… espero continues publicando material de calidad. suerte

Responder
mbruno 21/03/2011 - 18:24

Hola, me ha surgido una duda, que creo que está relacionada con RelativeLayout, te comento: ¿Es posible modificar la propiedad android:layout_x o android:layout_y en java?

Muchas gracias.

Responder
jdpt 23/04/2011 - 3:25

Muy buen tuto… muchas gracias!

Responder
David 30/05/2011 - 18:56

Hola Me podrian ayudar a crear una tabla desde codigo sin usar un .xml de antemano garcias.

Responder
soyfelix1 15/12/2011 - 11:19

Hola, una pregunta al respecto del parametro weight,
pones que si a un elemento le pones 1 y al otro 2, el segundo será el doble del otro.
No sería realmente que el primero se queda 1/3 del espacio libre y el segundo los 2/3 restantes?
es algo que aún no acabo de tener claro.
Muchas gracias

Responder
sgoliver 15/12/2011 - 12:25

Hola Felix, es lo mismo una cosa y otra. El doble de 1/3 es 2/3.

Responder
Alejandro 18/01/2012 - 13:50

Muchísimas gracias! Cada vez que leo un artículo tengo más ganas de empezar con el siguiente! Estoy aprendiendo muchísimo. mil gracias!!!

Responder
jose 28/02/2012 - 10:43

Una pregunta… dices: «a uno de ellos le establecemos un layout_weight=”1″ y al otro un layout_weight=”2″ conseguiremos como efecto que toda la superficie del layout quede ocupada por los dos cuadros de texto y que además el segundo sea el doble (relación entre sus propiedades weight) de alto que el primero.»
El problema es que a mi me pasa completamente al reves… el primer edittext es el doble de grande que el segundo…
como es eso posible?

Responder
alex 29/02/2012 - 17:17

Jose, a mi me pasa exactamente lo mismo, el primer EditText es el doble de grande que el segundo, no sé si estará mal en la web o estamos haciendo algo mal nosotros…yo creo que es mas lo segundo, jeje, que entre oliver y lo explique para aclararnos mejor..

Responder
Fernando G. 15/03/2012 - 9:26

El comportamiento de layout_weight se invierte sobre elementos que tienen el valor fill_parent, para corregirlo en vez de usar el fill parent hay que usar un valor igual a 0dp

Responder
BamsBamx 03/04/2012 - 17:21

MUCHISIMAS GRACIAS, DE VERDAD….. EL TUTORIAL CON EL QUE MAS ESTOY APRENDIENDO…(a ver si me saco unas perras….jejejej)

Responder
Men 04/05/2012 - 16:55

Hola, muy buen tutorial, pero seria bueno tambien que en los ejemplos de los Layout

pusieras unas imagenes que muestre la parte grafica del layout en el dispositivo, asi uno

se da una idea mas completa de como es que se ven, esos diferentes Layoutss

Responder
jose luis 23/05/2012 - 2:49

me gustaria programar para android…..esta super bien

Responder
Ravacho 22/09/2012 - 20:01

Excelente curso. Un pequeño bug que he encontrado. Aquí faltan unas comillas para cerrar el string.

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

Responder
Kikin 26/09/2012 - 11:47

Hola, solo darte la enhorabuena. El curso está genial, en breve encargaré mi manual en formato PDF.

Saludos y gracias

Responder
Pilar 23/01/2013 - 17:39

Tengo una duda, ¿cómo se indica el espacio que queremos que haya entre los distintos componentes en un tablelayout? Gracias.

Responder
juampa 24/01/2013 - 11:53

Lo primero darte las gracias por este fantástico manual.

En el ejemplo de GridLayout, no debería la propiedad android:rowCount ser igual a 3 y no a 2?

Responder
Javijav 25/03/2013 - 18:12

Hola,

Me gustaría saber como puedo hacer para descargar el código completo de los ejemplos de este artículo. Me gustaría descargarme el proyecto completo pero no encuentro ninguna opccion que me lo permita. Muchas gracias!!

Un saludo

Responder
Isrot 25/05/2013 - 2:15

Gracias por el todo este tutorial!!!
Mi pregunta es igual al de los anteriores… en LinearLayout al poner el weight me salen los tamaños al reves…. el «1» es mas grande que al que le pongo «2»…

Responder
Isrot 25/05/2013 - 2:34

Tambien quisiera saber porque cuando uso el TableLayout la pantalla me queda como si estubiera usando wrap_content y no match_parent…

me sale algo asi:
______________________________
|_1.1__|_1.2__|_1.3__|____________|
|_2.1__|_2.2__|_2.3__|____________|
|_3.1________|_3.2__|____________|
| |
| |
| |
| |
| |
| |
|______________________________|
|

Responder
María 18/06/2013 - 17:21

Hola,
He creado un tablelayout con campos dinamicos que tengo que rellenar y guardar, el problema me viene cuando quiero recorrer las filas dinamicas y sacar los datos que ha introducido el usuario, ¿Como podría hacerlo?
Saludos y gracias por adelantado!

Responder
Rolando 01/10/2013 - 17:08

Saludos Necesito ayuda e seguido el curso desde el primer capitulo pero ahora cuando intento hacer los ejemplos de este capitulo acerca de los Layout al correr mi emulador me sigue cargando la aplicacion de Hola Usuario realizada en el capitulo anterior. Cree un nuevo perfil para correr mi proyecto asignandole el proyecto respectivo y no me aparese el proyecto hecho corre el emulador pero no aparese la app. Espero su respuesta

Responder
quetal 02/01/2014 - 14:05

que significa weight? :P

Buen tutorial!
Gracias.

Responder
Cueto 31/01/2014 - 18:52

Saludos buena explicacion, me sirvio para darme una idea.

Responder
el corrector 10/02/2014 - 21:10

Muy buena la forma que tiene de estructurar y planificar los contenidos.

Por cierto (fe de erratas) «absorber» es con dos ‘b’ :)

Responder
sgoliver 11/02/2014 - 15:42

Vaya, un error bastante feo, gracias por el aviso, lo corrijo lo antes posible.

Responder
Julio 16/03/2014 - 9:53

Muy bueno el artículo. Sólo una cosilla: «absorber».

Responder
evicfrodo 23/03/2014 - 14:43

Puse el código de la TableLayout que aparece acá y no queda como mostrás en la imagen, los TextView se alinearon a donde quisieron y los textos no se centraron.

Responder
Fidel Rada 11/05/2014 - 21:21

disculpa en la universidad nos asen usar el AbsoluteLayout no tuvieras algún tutorial respecto a eso

Responder
admin 12/05/2014 - 9:38

Hola Fidel, el AbsoluteLayout está marcado como obsoleto en la documentación de Google desde la versión de Android 1.5 . Te recomendaría utilizar algún otro tipo de layout para tus aplicaciones. Saludos.

Responder
navyivan 26/06/2014 - 18:29

Hola, me gustaria hacer una «ventana» en donde tenga un encabezado para poner 2 o 3 botones y debajo llenarlo con un list adapter. como si fuera a seleccionar muchos archivos

Gracias

Responder
cristian 27/12/2014 - 5:59

muy buen tutorial mis respetos

Responder
Jesus de Prado 28/02/2015 - 18:25

Bien explicado, como los demás.

Responder
Jorge Luis 27/04/2015 - 17:47

Disculpa una pregunta como puedo ajustar un layout cuando por ejemplo pongo 10 optionbuttons y vuelvo 7 invisibles y solo salen 3?

El layout queda con el espacio en blanco y quiero evitar esto, gracias y saludos.

Responder
Joaquín Bresan 25/05/2015 - 19:25

Buen aporte amigo, gracias por compartir.

Responder
Dudas 08/07/2015 - 2:48

Tendras algun ejemplo que declares strings asi:

CREATE TABLE IF NOT EXISTS conversion (id_conv INTEGER PRIMARY KEY AUTOINCREMENT, fecha TEXT, celcius TEXT, fahrenheit TEXT)

para hacer la relacion con la base de datos?

Responder
Alexander 21/07/2015 - 17:01

Excelente trabajo

Responder
Alexander 21/07/2015 - 17:02

Excelente trabajo, gracias por compartir tu trabajo

Responder
kenny romero 20/08/2015 - 12:13

Buenos días , una pregunta , hace unas semanas vi un tutorial de card views de como pasar la información del card view y mostrarlo completo en otra actividad, no lo he vuelto a encontrar no se si sea de este sitio ?? Si me pudieras ayudar te lo agradecería . saludos

Responder
Antonio 16/10/2015 - 3:28

Yo hice este para el TableLayout y me quedó bien.

1

Responder
Facundo 09/11/2015 - 14:01

Acabo de empezar el curso. EXCELENTE hasta ahora. Muchas gracias por el aporte. Cuando termine el curso intentaré hacer un donativo :P
Abrazo!

Responder
Simarek 12/07/2016 - 9:05

Me gusto el curso recien empece, esta como debe ser todo un gran curso, Felicidades Salvador gracias por compartir sus conocimientos y presentarlos tan excelente trabajo de una manera que da gusto leer.

Saludos cordiales.

Responder
ren 26/07/2016 - 1:25

hola maestrazo soy tu hincha pero tengo un problema pasa que en la nueva version del android studio no puedo ejecutar tus proyectos sale una ventana para configurar framework y se ejecuta pero no se pueden ejecutar podrias decirme por que maestro

Responder
jhrodas 18/05/2017 - 13:40

Me gustaría tener siempre a la mano el curso. No encuentro un enlace para pago con tarjeta. Mil gracias.

Responder
Luis Franco 20/10/2017 - 19:48

Super bien explicado muchas gracias, por favor sube mas cosas asi.
saludos

Responder
Interfaz de Usuario Android: Botones | sgoliver.net 02/05/2020 - 12:57

[…] el capítulo anterior del curso vimos los distintos tipos de layouts con los que contamos en Android para distribuir […]

Responder

Dejar un comentario

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies