Orientación de la app restringida en teléfonos, pero no en pantallas grandes

Ícono de calificación de dos estrellas

Tu app funciona muy bien en teléfonos con orientación vertical, por lo que la restringiste a ese modo. Sin embargo, consideras que puedes aprovechar más las pantallas grandes en orientación horizontal.

¿Cómo puedes hacer las dos cosas: restringir la app a la orientación vertical en pantallas pequeñas y habilitar la orientación horizontal en pantallas grandes?

Prácticas recomendadas

Las mejores apps respetan las preferencias de los usuarios, como la orientación del dispositivo.

Los lineamientos de calidad de las apps adaptables recomiendan que estas admitan todas las configuraciones de dispositivos, incluidas las orientaciones vertical y horizontal, el modo multiventana y los estados plegado y desplegado de los dispositivos plegables. Las apps deben optimizar los diseños y las interfaces de usuario para diferentes configuraciones y deben guardar y restablecer el estado durante los cambios de configuración.

Esta receta es una medida temporal: una pizca de compatibilidad con pantallas grandes. Úsala hasta que puedas mejorar tu app para proporcionar compatibilidad total con todas las configuraciones de los dispositivos.

Ingredientes

  • screenOrientation: Es el parámetro de configuración del manifiesto de la app que te permite especificar cómo responde la app a los cambios de orientación del dispositivo.
  • Activity#setRequestedOrientation(): Es el método con el que puedes cambiar la orientación de la app en el tiempo de ejecución.
  • LocalConfiguration: Es un proveedor local de componibilidad que expone el Configuration actual del dispositivo, lo que te permite leer las dimensiones de la pantalla en dp.
  • LaunchedEffect: Es la API de efecto secundario de Compose que ejecuta un bloque de código cuando cambia una clave (en este caso, cuando cambia la configuración).

Pasos

Habilita la app para controlar los cambios de orientación de forma predeterminada en el manifiesto de la app. Luego, durante el tiempo de ejecución, usa Jetpack Compose para restringir de forma dinámica la orientación a vertical en pantallas compactas (teléfonos) y, al mismo tiempo, permitir todas las orientaciones en pantallas grandes.

1. Especifica la configuración de orientación en el manifiesto de la app

Puedes evitar declarar el elemento screenOrientation del manifiesto de la app (en cuyo caso, la orientación se establece de forma predeterminada como unspecified) o establecer la orientación de la pantalla como fullUser. Si el usuario no bloqueó la rotación basada en sensores, la app admitirá todas las orientaciones del dispositivo.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

La diferencia entre unspecified y fullUser es sutil, pero importante. Si no declaras un valor de screenOrientation, el sistema elige la orientación, y la política que usa para definirla puede diferir de un dispositivo a otro. Por otro lado, especificar fullUser coincide más con el comportamiento que el usuario definió para el dispositivo: si el usuario bloqueó la rotación basada en sensores, la app sigue la preferencia del usuario; de lo contrario, el sistema permite cualquiera de las cuatro orientaciones de pantalla posibles (vertical, horizontal, vertical inversa u horizontal inversa). Consulta android:screenOrientation.

2. Cómo restringir la orientación de forma dinámica en Compose

En Jetpack Compose, puedes leer las dimensiones actuales de la pantalla en dp de forma reactiva desde LocalConfiguration.current y usar un LaunchedEffect para actualizar la orientación de la actividad cada vez que cambie la configuración.

Si el ancho o la altura de la pantalla es inferior a 600dp (que corresponde al punto de interrupción compacto para teléfonos), restringe la orientación a vertical. De lo contrario, permite que el sistema rote la app según la preferencia del usuario (unspecified o fullUser).

Aquí tienes la implementación completa y compilable:

val configuration = LocalConfiguration.current
val context = LocalActivity.current

LaunchedEffect(configuration) {
    val activity = context ?: return@LaunchedEffect
    // Determine if screen is compact (phone-sized) in either width or height
    val isCompact = configuration.screenWidthDp < 600 || configuration.screenHeightDp < 600
    activity.requestedOrientation = if (isCompact) {
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    } else {
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    }
}

Si agregas la lógica dentro de un bloque LaunchedEffect(configuration), puedes anular de forma reactiva el parámetro de configuración de orientación cada vez que cambie la configuración de la app, como cuando se cambia el tamaño de la actividad, se mueve entre pantallas o cuando se pliega o se despliega un dispositivo plegable.

Para obtener más información sobre cuándo se producen los cambios de configuración y cuándo provocan recreación de actividad, consulta Cómo administrar los cambios en la configuración.

Resultados

Ahora la app debería permanecer en orientación vertical en pantallas pequeñas, independientemente de la rotación del dispositivo. En pantallas grandes, la app debería admitir la orientación horizontal y vertical.

Recursos adicionales

Si necesitas ayuda con la actualización de la app para admitir todas las configuraciones de dispositivos en todo momento, consulta lo siguiente: