18/05/2014
Debido a la amplísima diversidad de dispositivos móviles que ejecutan Android es imprescindible diseñar interfaces adaptadas a las resoluciones/densidades de pantalla más comunes y en numerosas ocasiones resulta necesario tener layouts distintos con el objetivo de que nuestra app utilice de forma óptima e inteligente toda la pantalla diponible ya se trate, por ejemplo,de una tablet de 7 pulgadas en posición horizontal (landscape) o de un móvil de 4″ en vertical.
Independientemente de las soluciones elegidas, es imprescindible al hacer un buen diseño utilizar siempre unidades relativas que puedan reescarlarse fácilmente de forma automática a cualquier tamaño de pantalla. En Android tenemos los siguientes tipos de unidades de medida para el diseño de interfaces:
- Fijas
- px:Representa un píxel.
- in : pulgada (25,4 mm) según el tamaño físico de la pantalla.
- mm: milímetro.
- pt: punto, la 1/72 parte de una pulgada.
- Relativas
- dp: Píxel independiente de la densidad. Permite definir un tamaño relativo a la densidad de píxeles en pantalla siendo 1 dp un píxel en una pantalla de densidad 160dpi. Para calcular su tamaño, tenemos que px = dp * (dpi / 160) y que el tamaño físico de la pantalla es irrelevante.
- sp: píxel independiente de la escala. Es equivalente a dp pero teniendo en cuenta la «escala» que el usaurio ha definido para el tamaño de las fuentes
Utilizaremos siempre que sea posible unidades dp (y sp para el tamaño de fuentes) para asegurar que los elementos de nuestros layout tengan el mismo tamaño físico (de forma no exacta pero muy aproximada) en cualquier pantalla. Con respecto a esto último, también tenemos que tener en cuenta que los dispositvos Android se clasifican según la densidad de su pantalla en las siguientes categorías que pueden usarse como cuantificadores para redefinir layout o cualquier otro fichero de recursos para una densidad especificada.
dpi | tipo | ejemplos |
120 | ldpi | Galaxy mini, HTC Wildfire |
160 | mdpi | Galaxy ACE, HTC Wildfire S |
213 | tvdpi | Nexus 7 2012 |
240 | hdpi | HTC Desire, LG G2, Galaxy S2, Galaxy ACE 2 |
320 | xhdpi | Nexus 7 2013, Galaxy Nexus,Nexus 4, Galaxy S3, Moto G |
480 | xxhdpi | Nexus 5, Galaxy S4, Galaxy S5, HTC One, Xperia Z |
640 | xxxhdpi |
Este valor se puede obtener programáticamente de forma sencilla:
DisplayMetrics metrics = getResources().getDisplayMetrics();
Es una buena práctica definir constantes para los tamaños que usemos puesto que lo habitual es que estos se repitan. Estas declaraciones se realizarán en un fichero de recursos normalmente denominado /res/values/dimens.xml.
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="small_button">32dp</dimen> <dimen name="normal_button">48dp</dimen> <dimen name="large_button">64dp</dimen> <dimen name="small_text">12sp</dimen> <dimen name="normal_text">14sp</dimen> <dimen name="large_text">16sp</dimen> </resources>
Estas constantes se usarían de la siguiente forma
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:textSize="@dimen/small_text"/> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:textSize="@dimen/normal_text"/> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:textSize="@dimen/large_text"/> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" android:textSize="@dimen/small_button"/> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" android:textSize="@dimen/normal_button"/> <Button android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button" android:textSize="@dimen/large_button"/> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:layout_gravity="center_horizontal"/> </LinearLayout>
La siguiente imagen muestra el layout en un Samsung Galaxy Nexus (4,65″, 315dpi) y en un Galaxy ACE (3.5″, 164 dpi )
Podemos hilar más fino todavía y establecer el tamaño de las dimensiones relativas de forma específica para cierta densidad/posición de pantalla. Para ello creamos los directorios /res/values-[densidad-resolucion]-[formato] que sean necesarios y ubicamos en los mismos la versión de dimens.xml correspondiente, por ejemplo /res/values-mdpi/dimens.xml, /res/values-sw600dp-land/dimens.xml…Es decir, procedemos de forma similar que cuando queremos especificar layouts o drawables en función de la pantalla del dispositivo.
El proyecto completo para Eclipse ADT se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.