Cómo brindar compatibilidad con diferentes tamaños de pantalla

Los dispositivos Android pueden tener diferentes formas y tamaños. Como resultado, el diseño de tu app debe adaptarse a ellos y ser responsivo. En lugar de definir el diseño con dimensiones estáticas para un tamaño de pantalla, una relación de aspecto o una orientación determinados, diseña tu app a fin de que se adapte correctamente a los distintos tamaños y orientaciones de la pantalla.

La compatibilidad con muchas pantallas permite que la app se encuentre disponible para la mayor cantidad posible de usuarios con dispositivos diferentes, mediante un único APK o AAB. Además, si diseñas tu app para diferentes tamaños de pantalla, se garantiza que esta pueda procesar cambios en la configuración de la ventana del dispositivo, como cuando el usuario accede al modo multiventana o cuando app se usa en un dispositivo plegable en el que el tamaño de la pantalla y la relación de aspecto cambian durante la ejecución.

Sin embargo, admitir diferentes tamaños y orientaciones de pantalla no necesariamente hace que tu app sea compatible con todos los factores de forma de Android. Debes realizar pasos adicionales para que sea compatible en Wear OS, TV, Auto y Chrome OS.

Si deseas obtener más información a fin de compilar IU para diferentes pantallas, consulta el artículo sobre diseño de Material Design.

Clases de tamaño de ventana

Las clases de tamaño de ventana son un conjunto de puntos de interrupción de viewports bien definidos de modo que crees, desarrolles y pruebes diseños de aplicaciones de tamaño variable. Se eligieron específicamente a los efectos de equilibrar la simplicidad del diseño con la flexibilidad con el propósito de optimizar la app en casos únicos.

Las clases de tamaño de ventana particionan el tamaño sin procesar de la ventana que esté disponible para tu app en buckets más administrables y significativos. Existen tres buckets: compacto, medio y expandido. El ancho y alto disponibles se particionan de manera individual, por lo que, en cualquier momento, tu app tiene dos clases de tamaño de ventana asociadas: una de ancho y una de alto.

Si bien las clases de tamaño de ventana se especifican tanto para el ancho como para el alto, el ancho disponible suele ser más importante que el alto disponible debido a la ubicuidad del desplazamiento vertical. Por lo tanto, es probable que la clase de tamaño de ventana de ancho resulte más relevante para la IU de tu app.

Representaciones de clases de tamaños de ventana basadas en el ancho.
Figura 1: Representaciones de clases de tamaños de ventana basadas en el ancho.
Representaciones de clases de tamaños de ventana basadas en el alto.
Figura 2: Representaciones de clases de tamaños de ventana basadas en el alto.

Como se indicó antes, estos puntos de interrupción te permiten seguir pensando en los diseños en términos de dispositivos y configuraciones. Cada punto de interrupción de clase de tamaño representa la mayoría de los casos en cada dispositivo típico, que puede ser un marco de referencia útil cuando piensas en el diseño de tus diseños basados en puntos de interrupción.

Clase de tamaño Punto de interrupción Representación del dispositivo
Ancho compacto Menos de 600 dp 99.96% de los teléfonos en orientación vertical
Ancho medio 600 dp o más 93.73% de las tablets en orientación vertical

Pantallas internas grandes y desplegadas en orientación vertical

Ancho expandido 840 dp o más 97.22% de las tablets en orientación horizontal

Pantallas internas grandes y desplegadas en orientación horizontal

En la mayoría de las apps, se puede llegar hasta aquí
Altura compacta Menos de 480 dp 99.78% de los teléfonos en orientación horizontal
Altura media 480 dp o más 96.56% de las tablets en orientación horizontal

97.59% de los teléfonos en orientación vertical

Alto expandido 900 dp o más 94.25% de las tablets en orientación vertical

Aunque es útil visualizar las clases de tamaño con dispositivos físicos, las clases de tamaño de ventana no están determinadas explícitamente por el tamaño físico de la pantalla. En otras palabras, las clases de tamaño de ventana no representan la lógica "isTablet". En cambio, están determinadas por el tamaño de ventana disponible para tu aplicación.

Esto tiene dos consecuencias importantes:

  • Los dispositivos físicos no garantizan una clase específica de tamaño de ventana. Existen muchos motivos por los que el espacio de pantalla disponible para tu app puede diferir del tamaño físico de la pantalla del dispositivo. En los dispositivos móviles, el modo de pantalla dividida puede dividir la pantalla entre varias aplicaciones. En Chrome OS, las apps para Android se pueden presentar en ventanas de formato libre cuyo tamaño puede cambiar de forma arbitraria. Los dispositivos plegables pueden tener varias pantallas físicas y, cuando se pliega el dispositivo, se cambia la pantalla visible.

  • La clase de tamaño de ventana puede cambiar durante el ciclo de vida de tu app. Mientras esta está abierta, rotar o plegar el dispositivo, y realizar varias tareas a la vez puede cambiar la cantidad de espacio de pantalla disponible. Por lo tanto, la clase de tamaño de ventana es dinámica, y la IU de tu app debería adaptarse según corresponda.

Usa los puntos de interrupción del tamaño de la ventana a fin de tomar decisiones de diseño de aplicaciones de alto nivel, como decidir usar un diseño canónico específico para usar espacio adicional en la pantalla. Estos también se asignan a los puntos de interrupción de diseño de Material Design a los efectos de realizar cambios en las columnas de la cuadrícula de diseño.

Si deseas calcular las clases de tamaño de ventana, las aplicaciones deben consultar las métricas de la ventana actual disponibles para la app, según lo proporciona la biblioteca WindowManager de Jetpack.

Vistas

enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ...

        // Replace with a known container that you can safely add a View
        // to where it won't affect the layout and the view won't be
        // replaced.
        val container: ViewGroup = binding.container

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged.
        // This is required for all activities, even those that don't
        // handle configuration changes.
        // We also can't use Activity.onConfigurationChanged, since there
        // are situations where that won't be called when the configuration
        // changes.
        // View.onConfigurationChanged is called in those scenarios.
        container.addView(object : View(this) {
            override fun onConfigurationChanged(newConfig: Configuration?) {
                super.onConfigurationChanged(newConfig)
                computeWindowSizeClasses()
            }
        })

        computeWindowSizeClasses()
    }

    private fun computeWindowSizeClasses() {
        val metrics = WindowMetricsCalculator.getOrCreate()
            .computeCurrentWindowMetrics(this)

        val widthDp = metrics.bounds.width() /
            resources.displayMetrics.density
        val widthWindowSizeClass = when {
            widthDp < 600f -> WindowSizeClass.COMPACT
            widthDp < 840f -> WindowSizeClass.MEDIUM
            else -> WindowSizeClass.EXPANDED
        }

        val heightDp = metrics.bounds.height() /
            resources.displayMetrics.density
        val heightWindowSizeClass = when {
            heightDp < 480f -> WindowSizeClass.COMPACT
            heightDp < 900f -> WindowSizeClass.MEDIUM
            else -> WindowSizeClass.EXPANDED
        }

        // Use widthWindowSizeClass and heightWindowSizeClass
    }
}

Vistas

public enum WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        // Replace with a known container that you can safely add a View
        // to where it won't affect the layout and the view won't be
        // replaced.
        ViewGroup container = binding.container;

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged.
        // This is required for all activities, even those that don't
        // handle configuration changes.
        // We also can't use Activity.onConfigurationChanged, since there
        // are situations where that won't be called when the configuration
        // changes.
        // View.onConfigurationChanged is called in those scenarios.
        container.addView(new View(this) {
            @Override
            protected void onConfigurationChanged(Configuration newConfig) {
                super.onConfigurationChanged(newConfig);
                computeWindowSizeClasses();
            }
        });

        computeWindowSizeClasses();
    }

    private void computeWindowSizeClasses() {
        WindowMetrics metrics = WindowMetricsCalculator.getOrCreate()
                .computeCurrentWindowMetrics(this);

        float widthDp = metrics.getBounds().width() /
                getResources().getDisplayMetrics().density;
        WindowSizeClass widthWindowSizeClass;

        if (widthDp < 600f) {
            widthWindowSizeClass = WindowSizeClass.COMPACT;
        } else if (widthDp < 840f) {
            widthWindowSizeClass = WindowSizeClass.MEDIUM;
        } else {
            widthWindowSizeClass = WindowSizeClass.EXPANDED;
        }

        float heightDp = metrics.getBounds().height() /
                getResources().getDisplayMetrics().density;
        WindowSizeClass heightWindowSizeClass;

        if (heightDp < 480f) {
            heightWindowSizeClass = WindowSizeClass.COMPACT;
        } else if (heightDp < 900f) {
            heightWindowSizeClass = WindowSizeClass.MEDIUM;
        } else {
            heightWindowSizeClass = WindowSizeClass.EXPANDED;
        }

        // Use widthWindowSizeClass and heightWindowSizeClass
    }
}

Compose

enum class WindowSizeClass { COMPACT, MEDIUM, EXPANDED }

@Composable
fun Activity.rememberWindowSizeClass() {
    val configuration = LocalConfiguration.current
    val windowMetrics = remember(configuration) {
        WindowMetricsCalculator.getOrCreate()
            .computeCurrentWindowMetrics(this)
    }
    val windowDpSize = with(LocalDensity.current) {
        windowMetrics.bounds.toComposeRect().size.toDpSize()
    }
    val widthWindowSizeClass = when {
        windowDpSize.width < 600.dp -> WindowSizeClass.COMPACT
        windowDpSize.width < 840.dp -> WindowSizeClass.MEDIUM
        else -> WindowSizeClass.EXPANDED
    }

    val heightWindowSizeClass = when {
        windowDpSize.height < 480.dp -> WindowSizeClass.COMPACT
        windowDpSize.height < 900.dp -> WindowSizeClass.MEDIUM
        else -> WindowSizeClass.EXPANDED
    }

    // Use widthWindowSizeClass and heightWindowSizeClass
}

Una vez que observes las clases de tamaño de ventana en tu app, estará todo listo para comenzar a cambiar tu diseño en función de la clase de tamaño actual. Si quieres obtener información para usar las clases de tamaño de ventana de modo que tus diseños basados en vistas resulten responsivos, consulta Cómo migrar tu IU a diseños responsivos. Si quieres obtener información para usar las clases de tamaño de ventana de modo que tus diseños basados en Compose resulten responsivos, consulta Cómo compilar diseños adaptables.

Lista de tareas para admitir diferentes clases de tamaño de ventana

A medida que realizas cambios, prueba el comportamiento de tu diseño en todos los rangos de tamaños de ventana, en especial, en los anchos de diseño compacto, medio y expandido.

Si ya tienes un diseño para pantallas más pequeñas, primero debes optimizarlo para la clase de tamaño de ancho expandido, ya que brinda más espacio para cambios adicionales de contenido o diseño. Luego, observa qué diseño resulta conveniente para la clase de ancho medio y considera agregar un diseño especializado en ese tamaño. Si deseas brindar una experiencia del usuario aún mejor, agrega funciones que tengan sentido en tu app, como la compatibilidad con distintas posiciones en dispositivos plegables o la optimización a fin de admitir las entradas de teclado, mouse y pluma stylus.

Obtén más información sobre los aspectos que hacen que una app resulte excelente en todos los dispositivos y tamaños de pantalla: consulta el artículo sobre la calidad de apps para pantallas grandes.

Cómo crear un diseño flexible

Independientemente del perfil de hardware con el que quieras brindar compatibilidad primero, debes crear un diseño que sea receptivo incluso para las variaciones más leves de tamaño de pantalla.

Cómo usar ConstraintLayout

La mejor manera de crear un diseño responsivo para diferentes tamaños de pantalla es usar ConstraintLayout como el diseño base en 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. De esta manera, todas las vistas pueden moverse y expandirse a la vez, a medida que cambia el tamaño de la pantalla.

La forma más fácil de compilar un diseño con ConstraintLayout es usar el editor de diseño de Android Studio, ya que te permite arrastrar nuevas vistas al diseño, asociar sus restricciones a la vista principal y a otras vistas relacionadas, y editar las propiedades de la vista, todo sin la necesidad de editar ningún archivo XML manualmente (consulta la Figura 1).

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

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

Aunque ConstraintLayout no resolverá todas las situaciones de diseño (en especial, en el caso de las listas cargadas de forma dinámica, donde deberás usar RecyclerView), no importa cuál sea el diseño que utilices, siempre debes evitar los tamaños de diseño hard-coded (consulta la siguiente sección).

Cómo evitar usar tamaños de diseño hard-coded

Para asegurarte de que tu diseño sea flexible y se adapte a diferentes tamaños de pantalla, debes usar "wrap_content" o "match_parent" para el ancho y el alto de la mayoría de los componentes de la vista, en lugar de los tamaños hard-coded.

"wrap_content" le indica a la vista que establezca el tamaño necesario para ajustar el contenido dentro de esa vista.

"match_parent" hace que la vista se expanda lo más posible dentro de la vista principal.

Por ejemplo:

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

Aunque el diseño real de esta vista depende de otros atributos en su vista principal y cualquier vista relacionada, esta TextView intenta establecer el ancho para rellenar todo el espacio disponible (match_parent) y configurar el alto de modo que sea exactamente igual al espacio requerido para la altura del texto (wrap_content). Esto permite que la vista se adapte a diferentes tamaños de pantalla y diferentes longitudes de texto.

La Figura 2 muestra cómo se ajusta el ancho de la vista de texto con "match_parent" a medida que cambia el ancho de la pantalla con la orientación del dispositivo.

Figura 2: Vista de texto flexible

Si usas un LinearLayout, también puedes expandir las vistas secundarias con ponderación de diseño para que cada vista rellene el espacio restante proporcionalmente a su valor de ponderación. Sin embargo, el uso de ponderaciones en un LinearLayout anidado requiere que el sistema realice varios pases de diseño a fin de determinar el tamaño de cada vista, lo que ralentiza el rendimiento de la IU. Por fortuna, ConstraintLayout puede lograr casi todos los diseños posibles con LinearLayout sin afectar el rendimiento, por lo que debes intentar convertir tu diseño a ConstraintLayout. Luego, puedes definir los diseños ponderados mediante cadenas de restricciones.

Cómo usar SlidingPaneLayout para IU de listas y detalles

Es posible que una IU de listas y detalles tenga que comportarse de manera diferente en distintos tamaños de pantalla. Cuando se ejecuta en una pantalla grande, hay mucho espacio para tener los paneles de lista y detalles en paralelo. Cuando haces clic en un elemento de la lista, se muestran sus detalles en el panel de detalles. Sin embargo, en pantallas más pequeñas, es posible que haya demasiada información. En lugar de mostrar ambos paneles, quizás sea mejor mostrarlos uno a la vez. Inicialmente, se muestra el panel de lista en toda la ventana. Cuando el usuario presiona un elemento, ese panel se reemplaza por el panel de detalles de ese elemento, que también ocupa toda la ventana.

Puedes usar SlidingPaneLayout a fin de administrar la lógica y determinar cuál de estas dos experiencias del usuario resulta apropiada para el tamaño de ventana actual:

<?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 anchos y la ponderación son los factores clave que determinan el comportamiento. Si la ventana es lo suficientemente grande para mostrar ambas vistas (580 dp como mínimo), se usa la IU en paralelo. Sin embargo, si es menor, la lista de pantalla completa se reemplaza por la IU de detalles de pantalla completa.

En el modo de lado a lado, la ventana puede ser más grande que el requisito mínimo de 580 dp de este ejemplo. Los valores de ponderación se usarán con el fin de ajustar el tamaño de los dos paneles de forma proporcional. En el ejemplo, el panel de lista siempre será de 280 dp y el de detalles rellenará el espacio restante. La única excepción se da cuando se usa SlidingPaneLayout V1.2.0-alpha01 y versiones posteriores en dispositivos plegables. En estos casos, SlidingPaneLayout ajustará automáticamente el tamaño de los paneles de modo que estén a ambos lados de la línea de plegado o bisagra.

Cómo crear diseños alternativos

Si bien el diseño siempre debe responder a diferentes tamaños de pantalla, ampliando el espacio entre las vistas y alrededor de estas, es posible que no brinde la mejor experiencia del usuario en todos los tamaños de pantalla. Por ejemplo, la IU que diseñaste para un teléfono probablemente no brinde una buena experiencia en una tablet. Por lo tanto, también debes proporcionar recursos de diseño alternativos a fin de optimizar el diseño de la IU en determinados tamaños de pantalla.

Figura 3: La misma app en pantallas de distintos tamaños usa un diseño diferente para cada una

Puedes proporcionar diseños específicos de la pantalla mediante la creación de directorios res/layout/ adicionales (uno para cada configuración de pantalla que requiera un diseño diferente) y, luego, agregar un calificador de configuración de la pantalla al nombre del directorio layout (como layout-w600dp para pantallas que tengan 600 dp de ancho disponible).

Esos calificadores de configuración representan el espacio de pantalla visible disponible para la IU de tu app. El sistema considera cualquier decoración (como la barra de navegación) y cambio en la configuración de la ventana (como cuando el usuario habilita el modo multiventana) cuando selecciona el diseño desde la app.

Para crear un diseño alternativo en Android Studio (con la versión 3.0 o una posterior) haz lo siguiente:

  1. Abre tu diseño predeterminado y, luego, haz clic en Orientation for Preview , en la barra de herramientas.
  2. En la lista desplegable, haz clic para crear una variante sugerida, como Create Landscape Variant, o haz clic en Create Other.
  3. Si eliges Create Other, aparecerá la opción Select Resource Directory. Aquí, deberás seleccionar un calificador de pantalla del lado izquierdo y agregarlo a la lista de Chosen qualifiers. Cuando termines de agregar calificadores, haz clic en OK. (Consulta las siguientes secciones para obtener información sobre los calificadores de tamaños de pantalla).

De esta manera, se crea un archivo de diseño duplicado en el directorio de diseño correspondiente, de modo que puedas empezar a personalizar el diseño de esa variante de pantalla.

Cómo usar el 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 o dip).

La descripción de Android del tamaño de la pantalla como una medida de píxeles independientes de la densidad te permite crear diseños para dimensiones de pantalla muy específicas y evitar cualquier preocupación que tengas respecto de las diferentes densidades de píxeles.

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

res/layout/main_activity.xml           # For handsets (smaller than 600dp available width)
res/layout-sw600dp/main_activity.xml   # For 7” tablets (600dp wide and bigger)

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 sencilla de especificar el tamaño de pantalla total 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: una pantalla típica de teléfono (240 x 320 ldpi, 320 x 480 mdpi, 480 x 800 hdpi, etc.)
  • 480 dp: una pantalla de teléfono grande de ~5" (480 x 800 mdpi)
  • 600 dp: una tablet de 7" (600 x 1024 mdpi)
  • 720 dp: una tablet de 10" (720 x 1280 mdpi, 800 x 1280 mdpi, etc.)

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

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

Recuerda que todas las cifras del calificador de ancho mínimo corresponden a píxeles independientes de la densidad, porque lo que importa es la cantidad de espacio de pantalla disponible luego de que el sistema calcule la densidad de píxeles (no la resolución de píxeles bruta).

Cómo usar el calificador de ancho disponible

En lugar de cambiar el diseño en función del ancho mínimo de la pantalla, puedes cambiarlo según el ancho o el alto disponibles actualmente. Por ejemplo, si tienes un diseño de dos paneles, puede que quieras usarlo cada vez que la pantalla proporcione un ancho mínimo de 600 dp, lo que podría variar en función de si el dispositivo se encuentra en orientación horizontal o vertical. En este caso, deberías usar el calificador de "ancho disponible" de la siguiente manera:

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

Si te preocupa el alto disponible, puedes hacer lo mismo con el calificador de "alto disponible". Por ejemplo, layout-h600dp para pantallas con al menos 600 dp de alto de pantalla.

Cómo agregar calificadores de orientación

Aunque puedes admitir todas las variaciones de tamaño con solo usar 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 las orientaciones vertical y horizontal.

Para eso, puedes agregar los calificadores port o land a los nombres del directorio de recursos. Asegúrate de que se ubiquen después de los otros calificadores de tamaño. Por ejemplo:

res/layout/main_activity.xml                # For handsets
res/layout-land/main_activity.xml           # For handsets 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 la tabla 2 de la guía acerca de Cómo proporcionar recursos.

Cómo modularizar componentes de la IU con fragmentos

Cuando diseñes tu app para varios tamaños de pantalla, asegúrate de no duplicar innecesariamente el comportamiento de la IU en las actividades. Para ello, debes usar fragmentos a fin de extraer la lógica de tu IU en componentes individuales. Luego, podrás combinar los fragmentos con el propósito de crear diseños de varios paneles cuando ejecutes la app en una pantalla grande o ubicarlos en actividades individuales cuando la ejecutes en un teléfono celular.

Por ejemplo, una app de noticias en una tablet podría mostrar una lista de artículos en el lado izquierdo y un artículo completo en el derecho (cuando seleccionas un artículo del lado izquierdo, se actualiza la vista del artículo en el lado derecho). Sin embargo, en un teléfono celular, estos dos componentes deben aparecer en pantallas separadas (cuando se elige un artículo de la lista, se cambia toda la pantalla para mostrarlo).

Si deseas obtener más información, consulta Cómo compilar una IU dinámica con fragmentos.

Cómo probar tu app en todos los tamaños de pantalla

Es importante que pruebes tu app en varios tamaños de pantalla a fin de asegurarte de que la IU se escale correctamente.

Android 10 (nivel de API 29) y las versiones posteriores admiten un rango más amplio de relaciones de aspecto. Con los dispositivos plegables, los factores de forma pueden variar desde pantallas muy largas y delgadas (como una proporción de 21:9 para un dispositivo plegado) hasta un tamaño de 1:1.

Para que tus apps admitan la mayor cantidad de dispositivos posible, deberías probarlas con todas estas proporciones de pantalla o con las que puedas:

Si no puedes admitir algunas de estas relaciones, usa maxAspectRatio (como antes) o minAspectRatio para indicar las relaciones más altas y más bajas que puede admitir tu app. En casos en los que las pantallas superan estos límites, es posible que se establezca el modo de compatibilidad en la app.

Cuando hay cinco íconos en la vista de navegación inferior en los dispositivos que ejecutan Android 10 (nivel de API 29) y versiones posteriores, se garantiza un tamaño de objetivo táctil mínimo de 2 pulgadas. Consulta el documento de Definición de compatibilidad.

Si no tienes acceso a dispositivos físicos de todos los tamaños de pantalla, puedes usar Android Emulator para emular cualquier tamaño de pantalla.

Si prefieres probarla en dispositivos físicos, pero no quieres comprarlos, puedes usar el Firebase Test Lab a fin de acceder a dispositivos en el Centro de Datos de Google.

Cómo declarar la compatibilidad con tamaños de pantalla específicos

Si no quieres que se ejecute tu app en determinados tamaños de pantalla, puedes establecer límites que especifiquen cuánto puede cambiarse dicho tamaño o incluso restringir los dispositivos que pueden instalar tu app en función de la configuración de la pantalla. Si deseas obtener más información, consulta Cómo declarar una compatibilidad de pantalla restringida.