Diseño responsivo/adaptable con vistas

Los diseños responsivos o adaptables proporcionan una experiencia del usuario optimizada sin importar el tamaño de la pantalla. Implementa diseños responsivos o adaptables para permitir que tu app basada en vistas admita todos los tamaños, las orientaciones y las configuraciones de pantalla, incluidas las configuraciones que pueden cambiar de tamaño, como el modo multiventana.

Diseño responsivo

El primer paso para admitir una variedad de factores de forma de dispositivos es crear un diseño que reaccione a las variaciones en el espacio de visualización disponible para tu app.

ConstraintLayout

La mejor manera de crear un diseño responsivo es usar ConstraintLayout como diseño base para tu IU. ConstraintLayout te permite especificar la posición y el tamaño de cada vista según las relaciones espaciales con otras vistas en el diseño. Luego, todas las vistas pueden moverse y cambiar de tamaño juntas a medida que cambia el espacio de visualización.

La forma más fácil de compilar un diseño con ConstraintLayout es usar el editor de diseño de Android Studio, El editor de diseño te permite arrastrar nuevas vistas al diseño, aplicar restricciones relacionadas con las vistas principales y secundarias, y configurar las propiedades de las vistas, todo sin editar ningún archivo XML manualmente.

Figura 3: El editor de diseño en Android Studio muestra un archivo ConstraintLayout.

Para obtener más información, consulta Cómo compilar una IU responsiva con ConstraintLayout.

Ancho y altura responsivos

A fin de garantizar que tu diseño sea responsivo para diferentes tamaños de pantalla, usa wrap_content, match_parent o 0dp (match constraint) para el ancho y la altura de los componentes de la vista en lugar de valores hard-coded:

  • wrap_content: La vista establece su tamaño para adaptarse al contenido que contiene.
  • match_parent: La vista se expande tanto como sea posible dentro de la vista superior.
  • 0dp (match constraint): Se encuentra en un ConstraintLayout, similar a match_parent. La vista abarca todo el espacio disponible dentro de sus restricciones.

Por ejemplo:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/lorem_ipsum" />

En la Figura 4, se muestra cómo se ajustan el ancho y la altura de TextView a medida que cambia el ancho de la pantalla con la orientación del dispositivo.

Figura 4: Una TextView responsiva

TextView establece su ancho para llenar todo el espacio disponible (match_parent) y su altura hasta el mismo espacio requerido por la altura del texto contenido (wrap_content), lo que permite que la vista se adapte a diferentes dimensiones de pantalla y diferentes cantidades de texto.

Si usas un LinearLayout, también puedes expandir las vistas secundarias según el peso del diseño, de modo que las vistas ocupen proporcionalmente el espacio disponible. Sin embargo, el uso de ponderaciones en un LinearLayout anidado requiere que el sistema realice varios pases de diseño para determinar el tamaño de cada vista, lo que ralentiza el rendimiento de la IU.

ConstraintLayout puede crear casi todos los diseños posibles con LinearLayout sin afectar el rendimiento, por lo que debes convertir tu LinearLayout anidado en ConstraintLayout. Luego, puedes definir los diseños ponderados mediante cadenas de restricciones.

Diseño adaptable

El diseño de tu app siempre debe ser responsivo para diferentes tamaños de pantalla. Sin embargo, incluso un diseño responsivo no puede proporcionar la mejor experiencia del usuario en todos los dispositivos o pantallas del modo multiventana. Por ejemplo, la IU que diseñaste para un teléfono probablemente no brinde una experiencia del usuario óptima en una tablet. El diseño adaptable proporciona diseños alternativos optimizados para diferentes dimensiones de pantalla.

SlidingPaneLayout para IUs de lista-detalles

Por lo general, una IU de lista-detalles proporciona una experiencia del usuario diferente en pantallas de diferentes tamaños. En pantallas grandes, los paneles de lista y de detalles suelen estar uno al lado del otro. Cuando se selecciona un elemento de la lista, la información del elemento se muestra en el panel de detalles sin cambiar la IU (los dos paneles permanecen uno al lado del otro). Sin embargo, en pantallas pequeñas, los dos paneles se muestran por separado y cada panel ocupa toda el área de visualización. Cuando se selecciona un elemento del panel de lista, el panel de detalles (que contiene la información del elemento seleccionado) reemplaza al panel de lista. La navegación hacia atrás reemplaza el panel de detalles por la lista.

SlidingPaneLayout administra la lógica a fin de determinar cuál de las dos experiencias del usuario es apropiada para el tamaño actual de la ventana:

<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/item_navigation" />

</androidx.slidingpanelayout.widget.SlidingPaneLayout>

Los atributos layout_width y layout_weight de las dos vistas que se encuentran en SlidingPaneLayout determinan el comportamiento de SlidingPaneLayout. En el ejemplo, si la ventana es lo suficientemente grande (al menos 580 dp de ancho) para mostrar ambas vistas, los paneles se muestran uno al lado del otro. Sin embargo, si el ancho de la ventana es inferior a 580 dp, los paneles se deslizarán uno sobre otro para ocupar toda la ventana de la app de forma individual.

Si el ancho de la ventana es mayor que el ancho mínimo total especificado (580 dp), se pueden usar valores layout_weight para ajustar el tamaño de los dos paneles de forma proporcional. En el ejemplo, el panel de lista siempre es de 280 dp de ancho porque no tiene un peso. Sin embargo, el panel de detalles siempre llena cualquier espacio horizontal que supere los 580 dp debido a la configuración layout_weight de la vista.

Recursos de diseño alternativos

Para adaptar el diseño de tu IU a una gran variedad de tamaños de pantalla, usa diseños alternativos identificados mediante calificadores de recursos.

Figura 5: La misma app con diferentes diseños para distintos tamaños de visualización

Puedes proporcionar diseños adaptables y específicos para la pantalla mediante la creación de directorios res/layout/ adicionales en el código fuente de tu app. Crea un directorio para cada configuración de pantalla que requiera un diseño diferente. Luego, agrega un calificador de configuración de pantalla al nombre del directorio layout (por ejemplo, layout-w600dp para pantallas que tengan 600 dp de ancho disponible).

Los calificadores de configuración representan el espacio de visualización visible disponible para la IU de tu app. El sistema tiene en cuenta cualquier decoración (como la barra de navegación) y cambio de configuración de la ventana (como el modo multiventana) cuando selecciona el diseño de tu app.

Para crear diseños alternativos en Android Studio, consulta Cómo usar variantes de diseño para optimizar para diferentes pantallas en Cómo desarrollar una IU con objetos View.

Calificador de ancho mínimo

El calificador de tamaño de pantalla de ancho mínimo te permite proporcionar diseños alternativos para pantallas que tienen un ancho mínimo medido en píxeles independientes de la densidad (dp).

Al describir el tamaño de la pantalla como una medida de dp, Android te permite crear diseños para dimensiones específicas de la pantalla sin preocuparte por las diferentes densidades de píxeles.

Por ejemplo, puedes crear un diseño llamado main_activity que esté optimizado para teléfonos y tablets creando diferentes versiones del archivo en distintos directorios:

res/layout/main_activity.xml           # For phones (smaller than 600dp smallest width)
res/layout-sw600dp/main_activity.xml   # For 7" tablets (600dp wide or wider)

El calificador de ancho mínimo especifica el lado más pequeño de la pantalla, independientemente de la orientación actual del dispositivo, por lo que es una manera de especificar el tamaño de pantalla general disponible para tu diseño.

A continuación, se muestra cómo los valores de ancho mínimo se corresponden con los tamaños de pantalla típicos:

  • 320 dp: pantalla pequeña de teléfono (240 x 320 ldpi, 320 x 480 mdpi, 480 x 800 hdpi, etcétera)
  • 480 dp: una pantalla de teléfono grande de ~5" (480 x 800 mdpi)
  • 600 dp: una tablet de 7" (600 x 1,024 mdpi)
  • 720 dp: una tablet de 10" (720 x 1280 mdpi, 800 x 1280 mdpi, etcétera)

En la siguiente figura, se proporciona una vista más detallada de cómo los diferentes anchos de dp de pantalla se corresponden con diferentes tamaños y orientaciones de pantalla.

Figura 6: Puntos de interrupción de ancho recomendados para admitir diferentes tamaños de pantalla

Los valores para el calificador de ancho mínimo son dp, porque lo que importa es la cantidad de espacio de visualización disponible después de que el sistema considera la densidad de píxeles (no la resolución de píxeles sin procesar).

Los tamaños que especificas con calificadores de recursos, como el ancho más pequeño, no son los tamaños de pantalla reales. En cambio, los tamaños especifican el ancho o alto en unidades dp disponibles para la ventana de tu app. El sistema Android puede usar una parte de la pantalla para la IU del sistema (como la barra del sistema en la parte inferior de la pantalla o la barra de estado en la parte superior). Por lo tanto, es posible que parte de la pantalla no esté disponible para tu diseño. Si tu app se usa en el modo multiventana, esta solo tendrá acceso al tamaño de la ventana que contiene la app. Cuando se cambia el tamaño de la ventana, se activa un cambio de configuración con el nuevo tamaño, que permite que el sistema seleccione un archivo de diseño apropiado. Por lo tanto, los tamaños del calificador de recursos que declares deben especificar solo el espacio que necesita tu app. El sistema considera cualquier espacio utilizado por la IU del sistema cuando proporciona espacio para el diseño.

Calificador de ancho disponible

En lugar de cambiar el diseño en función del ancho mínimo de la pantalla, te recomendamos que lo cambies según el ancho o la altura disponibles. Por ejemplo, es posible que quieras usar un diseño de dos paneles cada vez que la pantalla proporcione un ancho mínimo de 600 dp, lo que podría cambiar en función de si el dispositivo se encuentra en orientación horizontal o vertical. En ese caso, deberías usar el calificador de ancho disponible de la siguiente manera:

res/layout/main_activity.xml         # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # For 7" tablets or any screen with 600dp available width
                                     # (possibly landscape phones)

Si la altura disponible es importante para tu app, puedes usar el calificador de altura disponible. Por ejemplo, layout-h600dp para pantallas con al menos 600 dp de alto de pantalla.

Calificadores de orientación

Si bien es posible admitir todas las variaciones de tamaño con solo combinaciones de calificadores de ancho mínimo y ancho disponible, es posible que también quieras cambiar la experiencia del usuario cuando este alterne entre la orientación vertical y la horizontal.

Para ello, puedes agregar los calificadores port o land a los nombres del directorio de diseño. Solo asegúrate de que los calificadores de orientación aparezcan después de los calificadores de tamaño. Por ejemplo:

res/layout/main_activity.xml                # For phones
res/layout-land/main_activity.xml           # For phones in landscape
res/layout-sw600dp/main_activity.xml        # For 7" tablets
res/layout-sw600dp-land/main_activity.xml   # For 7" tablets in landscape

Para obtener más información sobre todos los calificadores de configuración de la pantalla, consulta Información general sobre los recursos de las aplicaciones.

Clases de tamaño de ventana

Las clases de tamaño de ventana son puntos de interrupción de viewport que te ayudan a crear diseños adaptables. Los puntos de interrupción identifican el área de visualización disponible para tu app como compacta, media o expandida. El ancho y la altura se especifican por separado, por lo que tu app siempre tiene una clase de tamaño de ventana para el ancho y una clase de tamaño de ventana para la altura.

Para aplicar diseños adaptables de manera programática, haz lo siguiente:

  • Cómo crear recursos de diseño basados en los puntos de interrupción de clase de tamaño de ventana
  • Calcula las clases de tamaño de ventana de ancho y alto de tu app con la función WindowSizeClass#compute() de la biblioteca Jetpack WindowManager.
  • Cómo aumentar el recurso de diseño para las clases de tamaño de ventana actuales

Para obtener más información sobre las clases de tamaño de ventana, consulta Cómo brindar compatibilidad con diferentes tamaños de pantalla.

Componentes de la IU modularizados con fragmentos

Cuando diseñes tu app para varios tamaños de pantalla, usa fragmentos a fin de extraer la lógica de la IU en componentes separados para asegurarte de no duplicar innecesariamente el comportamiento de la IU en las actividades. Luego, podrás combinar los fragmentos para crear diseños de varios paneles en pantallas grandes o colocarlos en actividades separadas en pantallas pequeñas.

Por ejemplo, el patrón de lista-detalles (consulta SlidingPaneLayout más arriba) podría implementarse con un fragmento que contenga la lista y otro fragmento con los detalles del elemento de lista. En pantallas grandes, los fragmentos podrían mostrarse uno al lado del otro; en pantallas pequeñas, individualmente en toda la pantalla.

Para obtener más información, consulta la descripción general de Fragments.

Incorporación de actividad

Si tu app consta de varias actividades, incorporarlas te permitirá crear fácilmente una IU adaptable.

La incorporación de actividades muestra varias actividades o varias instancias de la misma actividad simultáneamente en la ventana de tareas de una aplicación. En pantallas grandes, las actividades se pueden mostrar una al lado de la otra; en pantallas pequeñas, apiladas una sobre otra.

Para determinar la manera en que tu app muestra sus actividades, crea un archivo de configuración XML que el sistema use para determinar la presentación adecuada según el tamaño de la pantalla. También puedes realizar llamadas a la API de Jetpack WindowManager.

La incorporación de actividades admite cambios de orientación del dispositivo y dispositivos plegables, en los que se apilan y desapilan actividades a medida que el dispositivo rota o se pliega y se despliega.

Para obtener más información, consulta Incorporación de actividades.

Tamaños de pantalla y relaciones de aspecto

Prueba tu app en una variedad de tamaños de pantalla y relaciones de aspecto para asegurarte de que la IU se escale correctamente.

Android 10 (nivel de API 29) y las versiones posteriores admiten una gran variedad de relaciones de aspecto. Los factores de forma plegables pueden variar desde pantallas altas y angostas, como 21:9 cuando se pliegan, hasta una relación de aspecto cuadrada de 1:1 cuando se despliega.

Para garantizar la compatibilidad con la mayor cantidad posible de dispositivos, prueba tus apps con tantas relaciones de aspecto de pantalla como puedas:

Figura 7: Varias relaciones de aspecto de pantalla

Si no tienes acceso a dispositivos de todos los tamaños de pantalla que deseas probar, puedes usar Android Emulator para emular casi cualquier tamaño de pantalla.

Si prefieres realizar pruebas en un dispositivo real, pero no lo tienes, puedes usar Firebase Test Lab para acceder a dispositivos en el centro de datos de Google.

Recursos adicionales