«

»

oct 10 2011

Buenas prácticas: Implementación de interfaces

Con anterioridad os expusimos un conjunto de herramientas que nos proporcionaba la SDK de Android para optimizar nuestras aplicaciones para la multitud de tipos de pantalla que existen en el mercado, a continuación pasamos a enumeraros un conjunto de buenas prácticas a la hora de implementar nuestras interfaces que sin duda nos facilitaran las cosas.

Empezamos con una lista rápida de cómo asegurar que nuestras aplicaciones se muestren correctamente en diferentes pantallas:

  • Usar wrap_content, fill_parent, o unidades en dp cuando especifiquemos las dimensiones en laos ficheros XML de Layouts.
  • No usar pixeles reales a la hora de trabajar con bitmaps en el código de tu aplicación.
  • No utilizar AbsoluteLayout (es obsoleto).
  • Suministrar distintos bitmaps en función de la densidad.

En las siguientes secciones profundizaremos en el tema.

 

Usar wrap_content, fill_parent, o unidades en dp cuando especifiquemos las dimensiones en laos ficheros XML de Layouts

Cuando definamos el layout_width y layout_height en nuestros archivos XML, usaremos “wrap_content”, “fill_parent” o unidades dp para garantizar que la vista posea un tamaño apropiado independientemente de la pantalla en la que la visualicemos.

Por ejemplo, una vista con un layout_width = “100dp” medidas de 100 píxeles de ancho en una pantalla de densidad media el sistema la escalara hasta 150 píxeles de ancho en la pantalla de densidad alta, de modo que el elemento ocupara aproximadamente el mismo espacio físico en la pantalla.

Del mismo modo, debería optar por unidades sp (scale-independent pixel) para definir tamaños de texto.

 

No usar pixeles reales a la hora de trabajar con bitmaps en el código de tu aplicación

Android utiliza píxeles como unidad estándar para expresar los valores de dimensiones o de coordenadas. Esto significa que las funciones o métodos nos devolverán los resultado en pixeles pero siempre teniendo en cuenta la densidad actual de la pantalla. Por ejemplo, si myView.getWidth () devuelve 10, el punto de vista es de 10 píxeles de ancho en la pantalla actual, pero en un dispositivo con una pantalla de alta densidad, el valor devuelto puede ser de 15. Si utiliza valores de píxeles en el código de aplicación para trabajar con mapas de bits que no son pre-escala puede que tenga problemas por esto. Es por eso que a la hora de manipular los mapas de bits nos deberemos referir a los pixeles teniendo en cuenta que las medidas tienen en cuenta la densidad en tiempo de ejecución.

Más adelante os indicamos unas consideraciones adicionales en cuanto a la densidad.

 

No utilizar AbsoluteLayout (está obsoleto)

A diferencia de otros tipos de layouts, AbsoluteLayout obliga al uso de posiciones fijas y esto puede provocar fácilmente que no se trabaje bien con distinta pantallas. Es por esto que AbsoluteLayout está obsoleto (a partir de la versión 1.5 API Level 13) y en su lugar deberemos usar RelativeLayout que utiliza posiciones relativas en su lugar.

 

Suministrar distintos bitmaps en función de la densidad

Como nuestros bitmaps se mostraran a distintos tamaños reales en función de la densidad necesitaremos proporcionar distintos recursos para ajustarnos a las densidades que manejemos. Por ejemplo, considere un icono que desea mostrar en las pantallas de media y alta densidad. Sólo tienes que crear tu icono en dos tamaños diferentes (por ejemplo 100×100 para densidad media y 150×150 para alta) y poner dichos recursos en sus correspondientes carpetas res/drawable-mdpi/icon.png y res/drawable-hdpi/icon.png. Ya en un post anterior comentamos los distintos calificadores para las carpetas de recursos.

 

CONSIDERACIONES ADICIONES SOBRE DENSIDADES

En esta sección describiremos más acerca de cómo funciona Android escalando bitmaps en función de las diferentes densidades de pantalla y la forma en que podemos controlar cómo se dibujan los bitmaps en diferentes densidades.

Para entender mejor cómo soportar distintas cuando manipulemos gráficos en tiempo de ejecución, debemos de entender que el sistema ayuda a asegurar que se usa la escala adecuada para los bitmaps de la siguiente manera:

  • Pre-escalando los recursos (por ejemplo los drawables): Si no tenemos recursos específicos para la densidad actual el sistema el sistema carga los recursos predeterminados (la carpeta sin calificadores) y escala según sea necesario. El sistema supone que los recursos predeterminados están diseñados para mdpi (densidad media). Hay ocasiones que en las que podemos desear que android no pre-escale nuestros recursos, la manera más sencilla de evitarlo es colocar los recursos en una carpeta con el calificativo nodpi.
  • Auto-escalado de pixeles y dimensiones: En caso de que lo deseemos podremos deshabilitar el pre-escalado en nuestras aplicaciones estableciendo android:anyDensity a “false” en el manifest o programáticamente para un bitmap configurando inScaled a “false”. Es importante tener en cuenta que aunque evitemos el escalado las peticiones de información sobre tamaño se nos seguirán proporcionando en pixeles escalados y no reales. Por lo general, no se debe desactivar el pre-escalado, la mejor manera es usar las técnicas descritas con anterioridad para dar soporte a distintas pantallas.

 

Escalando Bitmaps en tiempo de ejecución
Si el sistema carga un bitmaps alojado en la memoria asume que está diseñado para una densidad media de pantalla, si no fuera el caso podríamos indicar para que densidad está diseñado y así evitar el pre-escalado si así procediera. Esto lo haríamos mediante la función setDensity() pasándole como parámetro una constante de densidad desde la clase DisplayMetrics, como DENSITY_HIGHT o DENSITY_LOW.
Si usamos BitmapFactory para crear bitmaps en tiempo de ejecución podemos indicar igualmente para que densidad está diseñado a partir del campo inDensity y el campo inScaled para especificar si el mapa de bits se escalara para ajustarse a las distintas densidades.

 

Conversión unidades dp a unidades de pixeles
En algunos casos, deberemos expresar las dimensiones de dp y luego convertirlos a los píxeles. Imagine una aplicación en la que se reconoce un desplazamiento o un gesto después de comprobar que el dedo del usuario se ha movido por un mínimo de 16 píxeles. En una pantalla de de densidad media, un usuario debe pasar por 16 píxeles / 160 dpi, lo que equivale a 1/10 de una pulgada (2,5 mm) antes de que el gesto sea reconocido. En un dispositivo con una pantalla de densidad alta (240 dpi), el usuario debe pasar por 16 píxeles / 240 dpi, lo que equivale a 1/15 de una pulgada (o 1,7 mm). La distancia es mucho más corta y la aplicación por lo tanto parecerá más sensible para el usuario.

Para solucionar este problema, el umbral gesto debe ser expresado en unidades dp y luego convertirlo a píxeles reales usando DisplayMetrics.density que nos proporcionara el factor de escala (es necesario sumar 0.5F para redondear la cifra hasta el numero entero más cercano cuando se realice la conversión).
Veamos un ejemplo:

 

1
2
3
4
5
6
7
8
9
// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;

// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

// Use mGestureThreshold as a distance in pixels...

 

Sin embargo para este tipo de prácticas se recomienda el uso de los valores de configuración para pre-escalados disponibles en ViewConfiguration.

 

Y con esto hemos terminado, esperamos que os sirva de ayuda.

 

Acerca del autor

JMPergar

Mobile Developer at @BeRepublic & Founder of @AndroCode. Silver Speaker & Member of Core Team at @GDGBarcelona.

  • http://www.loroestudio.com lolo

    Gracias por éste consejo, es superutil. Pero me gustaría saber si es posible coger una imagen, y una vez averiguados los pixeles reales (a partir de su dpi), decir cuánto mide en cm. Gracias.

    • http://www.linkedin.com/in/jmpergar JMPergar | Editor Jefe

      La densidad de pixeles indica el numero de pixeles por pulgadas, asi que obteniendo la densidad de la pantalla y el numero de pixeles podrias calcularlo facilmente. ¿Pero es esto realmente necesario? ¿Para que lo necesitas?