Crear aplicaciones compatibles con múltiples pantallas.
A la hora de desarrollar una aplicación Android deberemos tomar varias decisiones muy importantes, como puede ser, el nivel de API mínimo que vamos a soportar y el tamaño de pantalla de los dispositivos para los que nuestra aplicación va a estar optimizada.
En el primero de los casos cuanto menor sea el nivel del API nos aseguraremos un mayor mercado potencial de usuarios-dispositivos que van a poder descargar nuestra aplicación. A cambio, perderemos la posibilidad de utilizar las nuevas características que se van añadiendo en cada API así como tener que utilizar clases y métodos deprecados en vez de los que les sustituyen y que están más optimizados.
Lo mismo sucede respecto al tipo de pantallas que la aplicación va a tener en cuenta. Una de las ventajas de Android es que cualquier fabricante puede diseñar un teléfono, con las características que desee y utilizar como sistema operativo Android. También, permite, que no sólo sea un sistema operativo móvil, ya que puede utilizarse en múltiples dispositivos, relojes, tabletas, televisiones, etc. Sin embargo, el desarrollador tendrá que pensar qué tipo de dispositivos y tamaños va a querer que puedan utilizar su aplicación. Para ello, vamos a ver qué mecanismos nos ofrece Android para poder utilizar nuestra aplicación en distintas pantallas.
Esta documentación es aplicable a partir de Android 1.6 (API de nivel 4).
A la hora de ver cómo podemos soportar varias pantallas, debemos tener en cuenta tanto el tamaño como la densidad. Entendemos por tamaño, como la medida de la diagonal de la pantalla. La densidad es el número de píxeles dentro de un área física de la pantalla, medidas en dpi (dots per inch).
Por suerte, no vamos a tener que trabajar cada una de las posibles configuraciones, ya que Android trabaja con rangos tanto de tamaños como de densidades. Es decir, que no vamos a tener que crearnos un layout para cada tamaño de pantalla o densidad. Por ejemplo, un dispositivo con una pantalla de 3,5 pulgadas y otro con una pantalla de 4 pulgadas, entrarían dentro del mismo rango, con lo cual sólo deberíamos de optimizar un layout para ambos dispositivos.
Los rangos de tamaño de pantalla que vamos a poder manejar son:
- small: para pantallas pequeñas.
- normal:
- large: para dispositivos con pantallas grandes.
- xlarge: para el resto de los dispositivos con pantallas de aproximadamente más de 7 pulgadas.
A partir de Android 3.2 (Api 13), estos grupos son deprecados, a favor de las nuevas técnicas de manejo de pantallas, que se basan en el ancho de la misma y que veremos más adelante.
Igualmente, tenemos cuatro grupos generales para la densidad:
- ldpi: (low) para densidades bajas
- mdpi: (medium): densidades entre 130 y 180 dpis aproximadamente.
- hdpi: (high) para pantallas con densidades altas.
- xhdpi: (extra high) para pantallas con más de 270 dpis aproximadamente.
Estos grupos están organizados alrededor de la configuración básica formada por el tamaño normal y la densidad mdpi que corresponden con el primer dispositivo Android, el T-Mobile G1.
La densidad, es un elemento muy importante, pues pantallas con el mismo tamaño, y distinta densidad, van a tener diferente espacio disponible. Android utiliza dp (densidad independiente del píxel) como unidad de medida virtual que no depende de la densidad. Es equivalente a un píxel en una pantalla con una densidad de 160 dpi, que estaría en el rango de la densidad media. Utilizando esta medida, Android, realizará todo el proceso de conversión de tamaños a píxeles, lo que nos asegura la compatibilidad con los distintos tipos de densidad. En las aplicaciones podemos expresar medidas en píxeles, pero esto puede causar una mala visualización en pantallas con diferentes densidades.
El tamaño mínimo que tendrán que tener nuestros layouts en dps son:
- xlarge: al menos 960 dp x 720 dp
- large: 640 dp x 480 dp
- normal: 470 dp x 320 dp
- small: 426 dp x 320 dp.
Cuando creemos la aplicación, podremos crear recursos específicos, para cada grupo de tamaño y para cada grupo de densidad. Para el tamaño tendremos que crearnos distintos layouts y para la densidad deberemos proveer bitmaps con resoluciones diferentes.
Aplicaciones independientes de la densidad.
Una aplicación será “independiente de la densidad”, cuando conserve el tamaño físico (desde el punto de vista del usuario) de los elementos de la interfaz de usuario, cuando sea visualizado en pantallas con diferentes densidades.
Con el siguiente ejemplo, se comprende fácilmente, la importancia de conservar la densidad. Tenemos tres pantallas con distintas densidades y el mismo botón y la misma imagen en cada una (todos los tamaños los hemos expresado en píxeles). Sin embargo, en la pantalla con densidad más baja, el botón y la imagen se ven más grandes, mientras, que en la pantalla con la densidad mayor, estos elementos se ven más pequeños. Además, en la pantalla con densidad más baja, la imagen aparece píxelada.
Es lógico, si tenemos en cuenta, que la densidad es el número de píxeles que entran en un área física, en las pantallas con baja densidad, tendremos menos píxeles, con lo que una imagen de 32 × 32 píxeles ocupará más área física de pantalla. Y viceversa para pantallas con alta densidad.
En la siguiente imagen, vemos como se mostraría al usuario, los elementos anteriores, una vez que hemos asignado recursos para los distintos tipos de densidades. Ahora, las tres pantallas muestran los elementos de forma similar.
Para poder lograr que nuestros elementos se muestren idénticamente en cualquier densidad debemos expresar las medidas de los elementos en dps. Un botón con un tamaño de 64 dp x 64 dp tendrá el mismo tamaño (en dps) para cualquier densidad. El sistema será el encargado de transformar ese botón en los píxeles adecuados para que mantenga ese aspecto en cualquier pantalla.
Ya tenemos solucionado el problema del escalado de los elementos. Sin embargo, las imágenes, van a píxelarse. Para evitarlo, es necesario que creemos recursos alternativos para los bitmaps.
Si decidimos, que no queremos que nuestra aplicación sea soportada en todas las pantallas, deberemos indicar los dispositivos soportados en el fichero AndroidManifest.xml. De esta forma, un dispositivo que no esté soportado no podrá descargarse la aplicación. Para ello, tendremos que utilizar el elemento "<supports-screens>", indicando los grupos de tamaño o de densidad soportados.
Crear recursos para pantallas distintas.
Por defecto, trabajando con dps y el atributo “wrap_content”, Android redimensiona los layouts de nuestra aplicación, ajustándoles a la pantalla del dispositivo. Esto será suficiente para casi todos los casos. Sin embargo, puede, que en pantallas grandes, queramos aprovechar el mayor espacio para variar la distribución, poder separar más los elementos, ampliarles, etc, o en pantallas pequeñas tener que ajustar nuestro diseño a la disminución del espacio disponible. Para ello, es necesario crearnos un layout para cada grupo de tamaño que queramos que muestre un aspecto distinto. Estos layouts, hay que guardarles dentro de la carpeta resources. Para cada tamaño, crearemos una carpeta del tipo "layout-xlarge/", "layout-small/", etc.
Igualmente, para los bitmaps dibujables, Android, puede redimensionar los ficheros .png, .jpg, .gif y nine-patch(.9.png) intentando renderizarlos de forma correcta al tamaño físico de cada dispositivo. Si queremos asegurarnos, que se renderizan correctamente, tendremos que crearnos estos ficheros para cada grupo de densidades y almacenarlos en la carpeta "resources" en la carpeta correspondiente. Estas tendrán el formato "drawable-grupo_de_densidad", por ejemplo, "drawable-hdpi".
Un fichero nine-patch es básicamente un fichero png en el que se especifican dos regiones que son estirables. Si el sistema tiene que escalar la vista estira el nine-patch, pero sólo va a estirar las dos regiones especificadas. De esta forma, el mismo recurso, funcionará para distintos tipos de pantallas.
A la hora de crear los layouts, no hay que olvidarnos, que la pantalla puede mostrarse en orientación vertical u horizontal, con lo que el tamaño va a cambiar radicalmente. Es posible crearnos layouts específicos para cada orientación, guardándoles con el calificador "land" o "port".
Cuando creemos los nuevos bitmaps debemos respetar el ratio de escalado 3:4:6:8. Por ejemplo, para un bitmat de 48×48 píxeles que se utilice en una pantalla de densidad media deberíamos crear uno de 36×36 para densidades bajas (x0.75), 48×48 para densidades medias, 72×72 para densidades altas(x1,5) y finalmente 96×96 (x2) para las pantallas con densidades altas.
Trabajar con layouts para tablets a partir de Android 3.2
Todo lo referente a los cuatro grupos de tamaños de pantallas es sólo vigente hasta Android 3.2. A partir de esta versión, se ha creado un nuevo sistema de gestión de los tamaños de pantalla, basándose en el ancho o alto de las mismas, siempre expresado en dp.
Antes de definir el tamaño que vamos a necesitar para nuestro layout, debemos tener en cuenta, que Android puede usar elementos de la interfaz de usuario (como la barra de sistema en la parte inferior de la pantalla o la barra de estatus en la parte superior) . Así que no tendremos disponible todo el espacio de la pantalla para nuestro layout.
Tenemos disponibles los siguientes nuevos calificadores de recursos para crear nuestras carpetas contenedoras de los layouts:
- swdp: Por ejemplo, sw600dp o sw720dp. El tamaño que vamos a necesitar en el layout, indicado por la dimensión más corta del área de pantalla disponible. Es decir, el menor ancho o alto posible para la pantalla.
Si nos creamos un layout dentro del recurso “res/layout-sw600dp”, este se usará por el sistema, siempre y cuando la pantalla, da igual en la orientación en que esté, alcance los 600 dp.
- wdp: indica el ancho mínimo disponible en dp para poder utilizar los recursos. Si cambiamos la orientación se buscará un nuevo recurso que se corresponda con el nuevo ancho. Por ejemplo, w720dp.
- hdp: Por ejemplo, h720dp o h1024dp. Igual que el anterior, pero en este caso, se controla el tamaño de la altura de la pantalla.
Veamos unos ejemplos de tamaños mínimos en dp para distintos dispositivos:
- 320 dp: para un teléfono normal (240×320 ldpi, 320×480 mdpi, 480×800 hdpi, etc).
- 480 dp: para tablets pequeñas (480×800 mdpi).
- 600 dp: para una tablet de 7 pulgadas (600×4024 mdpi).
- 720 dp: para tablets grandes, de 10 pulgadas (720×1280 mdpi, 800×1280 mdpi, etc).
Si quisiésemos crear una aplicación para un teléfono y una tablet (y el menor tamaño que van a poder tener las tablets, para poder usar el layout personalizado es de 600dp) tendríamos dos recursos:
- res/layout/main_activity.xml. Para el teléfono móvil.
- res/layout-sw600dp/main_activity.xml. Para las tablets.
Si necesitamos, especificar un layout diferente, para pantallas de 600dp y de 720dp, tendríamos un recurso más:
- res/layout-sw720dp/main_activity.xml.
En estos casos, no importa si el ancho viene dado por la orientación horizontal o vertical. Si queremos, utilizar un layout sólo cuando el ancho sea superior a 600 dp tendremos que crearnos el recurso:
- res/layout-w600dp/main_activity.xml.
Si cambiamos la orientación, y el tamaño del ancho es menor de 600, se utilizará el layout del recurso: res/layout/main_activity.xml.
Al igual que ocurría con los primeros grupos genéricos de tamaño, debemos declarar en el AndroidManifest.xml qué tamaños va a soportar nuestra actividad. Utilizaremos el mismo elemento "supports-screens" con el nuevo atributo "android:requiresSamallestWidthDp", con el que indicamos el ancho mínimo necesario para poder utilizar la aplicación.
Reader Comments (6)
Hola, este método de poner las medidas con "dp" no funciona, ya que no te ajusta un botón a todo tipos de pantalla, lo acabo de probar y en las de más densidad se ve mas pequeño y en las de más densidad se ve mas grande, no las queda de la misma medida tal y como se ve en la segunda imagen.
Un saludo.
Hola Jose,
tienes razón, en que utilizando el emulador no parece en ningún momento que se represente le botón con el mismo tamaño en diferentes densidades. Creo que el problema está relacionado con el emulador. He probado a obtener el tamaño de la pantalla, la densidad y el tamaño en píxels de un botón trabajando con tres tipos de densidades distintas.
El botón lo he declarado con un ancho de 200dp y un alto de 80dp.
Si partimos de la densidad base, que sería la media, el resultado que obtengo es que la escala de la densidad es 1, la densidad 160 (que es la que indico en el AVD) y el tamaño del botón 80x200 pixels.
La misma prueba en una densidad baja, de 120, me da una escala de 0.75 y el tamaño del botón es de 60x150. Que en efecto es el resultado de multiplicar el tamaño en la densidad base por esa escala.
Finalmente en la densidad alta, el botón mide 120x300 pixels, en una escala de 1.5.
No sé si te habrás fijado, pero en la pantalla de inicio del emulador, la del wallpaper, todo lo que se muestra tampoco está respetando la densidad. Incluso si le aplico una densidad muy alta, no entran todos los textos.
He visto que hay más gente que tiene el mismo problema pero nadie ha solucionado el problema.
Voy a investigar un poco más a ver si consigo encontrar alguna respuesta.
Un saludo.
Lo de los dp es un buen intento pero sólo funciona "bien" en pantallas con unas proporciones dadas, sin embargo hay tabletas más alargadas que otras por ejemplo.
En mi opinión lo que funciona "bien" es usar porcentajes para todo pero eso implicaría que los paddings, los margins, todo, pudiera declararse de forma porcentual respecto a algo, por desgracia no es así por lo que yo cada vez veo más clara la necesidad de pasar del sistema de posicionamiento de Android y usar código, es la única forma en la que tengo la seguridad de que tal o cual elemento tiene las dimensiones proporcionales que yo quiero, en las partes en las que lo he aplicado estoy muy satisfecho aunque supone mucho más trabajo.
Además que el porcentaje creo que es algo muy intuitivo. Pero no lo han usado ni en el weight, y eso que al final es lo que acabas pensando, qué porcentaje quieres dedica a cada elemento.
Yo estoy creando aplicaciones para IOS y Android con una plataforma online.
Es muy fácil e intuitiva y tiene muchas opciones guiadas para crear tantas pantallas como se desee.
En cuanto al tamaño, se autoescala y si tienes objetos dentro de la pantalla, se autoescalan según un %, de manera que se ve perfectamente en cualquier dispositivo, tenga el tamaño que tenga.
Pesé a ser una plataforma para gente sin conocimientos de programación, está muy abierta a developers, ya que permite incluso meter código html en la pantalla, es decir puede programar tu pantalla desde 0.
El resultado es una pp nativa multiplataforma.
Os paso el link:
www.nimbosolutions.com
Una consulta. Supongamos una aplicación que tiene una cierta actividad con varios elementos, por ejemplo varias opciones para elegir. Diseñando eso para una tableta de 10'' se podría poner todo en una misma página, pero si quisiéramos hacerlo compatible con un teléfono pequeño seguramente eso no sea lo mejor y sería deseable separarlo en varias páginas. Esto como se haría? Muchas gracias.