Creando los layouts de Meneadroid. Parte I

¡Hola!

Varias personas me han preguntado sobre el layout de Meneadroid. Que si como lo he hecho, que si he utilizado otra cosa, que si con layouts no se puede, etc. Y es que parece que los layouts se le atragantan a mucha gente que empieza con el mundo Android.

La verdad, yo al principio pensaba igual. Esto de los layouts es un peñazo, no se puede hacer nada bien, etc. Pero poco a poco, los fui entendiendo, hasta que se produjo la “singularidad”, es decir, vi como tenían que usarse. Y oiga, desde entonces, como dice el anuncio “hago lo que quiero, con mí… layout”. Y estoy encantado. Ojalá los hubiese conocido antes.

Por eso mismo, he decidido empezar una serie de posts explicando como he hecho el layout de Meneadroid. Empezaré por el menú principal, y luego iré explicando otras cosas, incluso, como he hecho los iconos tirando de Photoshop. Si esperáis que os diga que posts voy a escribir y de que irá cada uno, ya os digo que le estáis pidiendo a la persona equivocada que se organice y tenga capacidad de preparar cosas de antemano (madredelamorhermoso, pedirme eso a mí). Lo que intento es explicar cómo funcionan los Layouts y sus componentes y propiedades más importantes a través de esta interfaz.

Estos artículos van dirigidos a gente que ha empezado a pelearse con los Layouts y todavía está en la fase “odio los layouts” (sí, yo también pasé por ahí), pero si empezáis de cero, os recomiendo leer algo de documentación básica sobre layouts, ya que hay una serie de cosas que doy por supuestas. Y si no, pues preguntad, que responderé a gusto.

A lo que iba. Cuando cree la interfaz de Meneadroid tenía claro que mi patrón de diseño iba a ser la aplicación de Twitter (ver: http://android-developers.blogspot.com/2010/05/twitter-for-android-closer-look-at.html). Por lo tanto, tenía claro como quería que fuese el menú principal, y el resultado final fue este:

Bonico ¿eh?

Por supuesto hice infinidad de pruebas, prototipos y variaciones. Os pondría los prototipos que hice en papel, pero mi hija decidió que ganaban mucho siendo cortados en trocitos.

El contenedor principal

El contenedor principal es un LinearLayout con las siguientes propiedades destacables:

  • Orientation: vertical
  • Layout height: fill_parent
  • Vertical height: fill_parent

Nada del otro mundo. Simplemente, llenamos toda la pantalla con este View.

Dos de un tipo y dos del otro

Ahora agregamos dos LinearLayout y dos TextView según la imagen:

Vamos a hablar primero de los TextView, que son sencillitos, y así nos los quitamos de encima.

La manzana de Newton

En principio, no tienen nada especial, son dos TextViews con las siguientes propiedades:

  • Layout height: wrap_content
  • Layout width: fill_parent
  • Gravity: center

Hablemos sobre la gravedad de los View. La gravedad define cómo se va a alinear un objeto tanto vertical como horizontalmente. Existen dos propiedades que afectan a la gravedad: Gravity y Layout gravity. La primera, Gravity, nos indica cómo se va a alinear el contenido del View, mientras que el segundo, Layout gravity, nos indica cómo se va a alinear el View dentro de su contenedor padre. Pongo un par de ejemplos, fijaos en el recuadro rojo, que es el que me marca exactamente los bordes del View.

Ejemplo 1

  • Layout height: wrap_content
  • Layout width: fill_parent
  • Layout gravity:
  • Gravity: center

Este es el resultado actual. El View ocupa todo el ancho de su contenedor padre (en este caso el root View, por lo que ocupa toda la pantalla).

Además, como su Gravity es center, el testo sale centrado.

Layout gravity está en blanco ya que como ocupa todo el ancho, nos da igual centrar el View o no centrarlo.

Ejemplo 2

  • Layout height: wrap_content
  • Layout width: wrap_content
  • Layout gravity: center
  • Gravity:

Aquí hay una diferencia sutil. En este caso tenemos el width a wrap_content, por lo que el View ocupa el espacio exacto que necesita para mostrar el texto. Y al poner Layout gravity a center el widget queda centrado.

Resultado: tenemos la misma interfaz de cara al usuario, pero en realidad se comporta diferente.

Más manzanas

Es fundamental saber cuándo utilizar Gravity y cuando utilizar Layout gravity, y eso solo se obtiene a golpe de experiencia. Haced pruebas con TextView multilíneas para ver cómo se comportan las diferentes combinaciones. Algunos controles no disponen de Gravity (por ejemplo el ImageView). En ese caso, lo que suelo hacer es envolverlo con un Linear Layout y posicionar la imagen en él.

Los dos grandotes

Bien, vamos a hablar sobre los dos Layout que contienen el título de la aplicación y las opciones.

Por motivos estéticos, decidí que las tres filas debían respetar la misma proporción, es decir, un tercio del espacio sobrante sería para el título, otro tercio para las dos primeras opciones (Portada y Pendientes) y el último tercio para las otras dos (Buscar y Opciones).

De Layout width no nos vamos a preocupar, que está como wrap_content en el primer Layout y como fill_parent en el segundo. Pero del Layout height sí que vamos a hablar. Cómo sabéis, hay tres opciones: fill_parent, wrap_content y tamaño fijo. Las dos últimas las descartamos, ya que queremos que ocupen todo el espacio sea cual el tamaño de pantalla. Entonces, utilizaremos fill_parent.

Pero ¿qué sucede si establezco la propiedad Layout height como fill_parent en ambos casos? Pues que tendré un bonito Layout que tan solo muestra el logotipo. Tened en cuenta que fill_parent significa exactamente eso, llenar el padre, por lo tanto, el primer control con fill_parent llena toda la pantalla.

Busquemos otra solución. ¿Qué tal si ponemos el primer Layout como wrap_content y el segundo como fill_parent? Pues pasan dos cosas. Una, que no consigo la proporción en tercios que quería, y dos, que los dos TextView del final son expulsados fuera de la pantalla.

Es ahora cuando entra en juego el peso de los elementos a través de la propiedad Layout weight.

Weight Watchers

La propiedad Layout weight es un entero que especifica la proporción del espacio disponible que nuestro View va a ocupar. Bueno, en realidad especificamos el valor inverso. Imaginemos que tengo los siguientes Views con unos valores para tamaño:

  • View 1: wrap_content
  • View 2: fill_parent
  • View 3: fill_parent
  • View 4: wrap_content

Si no especificamos ningún peso para ninguno de ellos, veremos View1 en la parte superior ajustado a su contenido y debajo View2 ocupando todo el espacio restante.

Si le damos un peso de 1 a View2, entonces View3 ocupa todo el espacio libre debajo de View1. Básicamente, no es buena idea dentro de un mismo layout mezclar Views con el valor fill_parent con y sin peso.

Si establecemos un peso de 1 para View2 y View3, entonces veremos todos los elementos. View1 en la parte superior ajustado a su contenido, View4 en la parte inferior ajustado a su contenido, y en medio, View2 y View3 repartiéndose el espacio sobrante.

Pero ¿cómo hacemos que ocupen un espacio diferente? Pues asignándoles pesos diferentes. Recordad que el valor que asignemos es la inversa del espacio que ocupará. Así, si damos a View2 le damos un peso de 1 y a View3 se los damos de 2, View3 ocupará la mitad de espacio que View1. Si utilizamos la combinación 1 y 3, pues un tercio, etc. Os recomiendo que juguéis con estos números para ver cómo se comportan.

Entonces, como os comentaba, el LinearLayout que contiene el título tiene un valor de Layout weight de 2, y el TableLayout tiene un peso de 1, así, Android divide el espacio que queda entre estos dos componentes, y le da al primero la mitad que al segundo, lo que viene siendo 1/3 y 2/3 respectivamente.

Cómo siempre digo, ahora a practicar, practicar y practicar. He comentado dos conceptos muy importantes en este artículo, la gravedad y el peso de un widget. Conocerlos y aprender a usarlos es clave.

En el próximo artículo acabaremos de crear el menú, aunque una vez entendido esto, el resto es un paseo.

¡Hasta la próxima!

P.D.: ¿Qué no tienes Meneadroid? pues nada, aquí tienes el enlace:

Discover more Android apps

17 Comments

  1. Manu · November 1, 2010 Reply

    Muy bueno el post, gracias por compartir conocimiento 😉

  2. Tweets that mention Creando los layouts de Meneadroid. Parte I : Sergi & Replace -- Topsy.com · November 1, 2010 Reply

    […] This post was mentioned on Twitter by Manu Mora and Jordi Bernabeu, Sergi & Replace. Sergi & Replace said: Nuevo artículo, que digo, articulazo en sergiandreplace.com: Creando los layouts de Meneadroid. Parte I. http://kcy.me/lgf […]

  3. Sloy · November 9, 2010 Reply

    El artículo fantástico, yo estoy precisamente en esa etapa de odio a los layouts, y tenía esperanza de salir de ella :p
    Tengo algo atragantado gravity y weight, ahora me queda bastante más claro. Seguiré intentando mejorar mis interfaces mientras espero esas partes que faltan.
    Muchas gracias! 😉

  4. Luismi · November 12, 2010 Reply

    El artículo me parece buenísimo, nos viene de perlas a la gente que nos queremos iniciar en Android.
    Espero con mucho interés que salga la segunda parte.

    Muchas gracias! 😉

  5. Jaume · November 12, 2010 Reply

    Sergi!

    Para cuando la parte 2?

    La esperamos impacientemente! :)

    Gracias!

  6. sergi · November 12, 2010 Reply

    Hola

    Gracias a todos por vuestros comentarios, la verdad, no esperaba que gustase tanto.

    Esto anima mucho a continuar, a ver si la próxima semana tengo tiempo de hacer la segunda parte. Ya avisé que no soy bueno para planificar cosas :)

    Saludos!

  7. duvel · November 23, 2010 Reply

    Hola, puedes poner como queda el xml completo… muchas gracias, es muy util el tutorial

  8. Onetx · November 24, 2010 Reply

    Muy útil el tutorial, muy ameno y practico. Te animo a continuar escribiendo!

  9. Manu · December 25, 2010 Reply

    Muy buenas. A ver si lo he entendido bien, la estructura es algo así:
    LinearLayout
    LinearLayout /LinearLayout
    TableLayout
    TableRow
    Button/
    Button/
    /TableRow
    TableRow
    Button/
    Button/
    /TableRow
    /TableLayout
    TextView /TextView
    TextView /TextView
    /LinearLayout

    El problema que tengo es que dentro de cada pongo dos botones tipo imagen pero los tengo alineados a la izquierda, les pongo gravity=”center” pero no hay forma de centrarlos…
    Otra duda es si el texto del botón (Portada, pendientes, buscar y opciones) va incorporado a la imagen, o el texto va a parte con un textview.

    Mil gracias por tu tiempo :)

  10. sergi · December 25, 2010 Reply

    Hola manu

    Lo primero no acabo de pillar la pregunta, ya que tu ejemplo sale desalineado

    La segunda, no, la imagen es un control y el texto otro, que están dentro de un LinearLayout (vertical). Es este LinearLayout el que recibe el evento OnClick.

    A todos los que me han pedido la segunda parte, disculpas por el largo tiempo. La tengo a medias, pero el trabajo de ser padre va por delante de cualquier cosa.

    A ver si aprovechando las fiestas…

  11. Jordi · January 14, 2011 Reply

    Muy buen artículo!
    La verdad es que con esto me olvido de los AbsoluteLayouts, que hasta ahora era con lo único que conseguía maquetar algo decente.

    Gracias!

  12. Alf · January 18, 2011 Reply

    Gracias por el artículo. Me ha sido muy útil.

  13. Alberto · April 13, 2011 Reply

    Hola Sergi, utilizo a diario meneadroid desde hace un tiempo y ahora estoy intentando meterme en esto de hacer cosillas para Android. Sé que lo que te voy a preguntar no tiene que ver con el post que has hecho así que te pido disculpas anticipadamente. Una vez que pulsas el boton de portada, se muestra un listado bastante completo que combina imagenes y diferentes tipos de textos. Mi primera duda es, este listado es un ListView o es otro control diferente? Para la aplicación que estoy montando necesito mostrar un listado que tenga por cada elemento varias lineas con dos tipos de fuentes diferentes algo como lo que tu tienes montado, que pone el titular de la noticia y abajo en chico la url de la noticia. ¿Podrías iluminarme un poco o decirme algúna web de donde hayas sacado información?

    Un abrazo y gracias por todo.

  14. Alexis G · December 16, 2011 Reply

    Saludos muy buen artículo yo lo tengo casi ready el unico problema es cuando pongo los imageboton en los rows se distorcionan. Como hago para que se vean como son y no se expandan. Gracias por todo.

  15. sergi · December 18, 2011 Reply

    Hola Alberto

    La activity como bien dices contiene un listview. Los comentarios en un principio iba a crearlos con un ListView dentro de cada item del ListView principal, pero eso lleva más dolores de cabeza que otra cosa. Así que construí una view que los genera en tiempo real como hijos de un linearlayout. Probablemente hoy lo haría algo más refinado, pero esto tiene casi dos años y sabía bastante menos que ahora sobre el tema.

    Alexis (y todos los demás) con tan poca info es dificil contestar. ¿Por que no te pasas por el foro de Catdroid? Allí, yo y otros podremos ayudarte mejor: https://groups.google.com/forum/?hl=en#!forum/catdroid

    Saludos!

  16. Adela · April 7, 2013 Reply

    Podrías poner el XML para echarle un ojo??

  17. Roberto · April 8, 2013 Reply

    Hola buenas tardes.
    oye tengo algunas dudas con los layout, cuando se crea un layout esta en forma vertical y le hay haces el diseño, pero que pasa al momento que pones en forma horizontal se pierde el diseño orginal.
    mi pregunta es como puedo hacer para que mi diseño se mantenga en forma vertical y horizontal.???
    hay algun layout que sea auto agustable y no se puerda el diseño ?.

Leave a Reply