Los desarrolladores suelen encontrar dificultades únicas cuando crean aplicaciones para dispositivos plegables, en especial, dispositivos como el Samsung Trifold o el Pixel Fold original, que se abre en formato horizontal (rotation_0 = horizontal). Entre los errores de los desarrolladores, se incluyen los siguientes:
- Suposiciones incorrectas sobre la orientación del dispositivo
- Casos de uso pasados por alto
- No volver a calcular ni almacenar en caché los valores en los cambios de configuración
Entre los problemas específicos relacionados con el dispositivo, se incluyen los siguientes:
- Una falta de coincidencia en la orientación natural del dispositivo entre las pantallas de la cubierta y la interna (suposiciones basadas en rotation_0 = vertical), lo que provoca que las apps fallen en los recorridos de plegado y desplegado
- Diferentes densidades de pantalla y manejo incorrecto del cambio de configuración density
- Problemas de vista previa de la cámara causados por la dependencia del sensor de la cámara en la orientación natural
Para ofrecer una experiencia del usuario de alta calidad en dispositivos plegables, enfócate en las siguientes áreas críticas:
- Determina la orientación de la app en función del área de pantalla real que ocupa la app, no la orientación física del dispositivo.
- Actualiza las vistas previas de la cámara para administrar correctamente la orientación del dispositivo y las relaciones de aspecto, evitar las vistas previas laterales y evitar las imágenes estiradas o recortadas.
- Mantén la continuidad de la app durante el plegado o el desplegado del dispositivo reteniendo el estado con
ViewModelo enfoques similares, o bien controlando manualmente los cambios de densidad y orientación de la pantalla, lo que evita que se reinicie la app o se pierda el estado. - En el caso de las apps que usan sensores de movimiento, ajusta el sistema de coordenadas para que se alinee con la orientación actual de la pantalla y evita las suposiciones basadas en rotation_0 = vertical, lo que garantiza interacciones precisas del usuario.
Compilación adaptable
Si tu app ya es adaptable y cumple con el nivel optimizado (Nivel 2) que se describe en los lineamientos de calidad de las apps adaptables, la app debería funcionar bien en dispositivos plegables. De lo contrario, antes de volver a verificar los detalles específicos de los dispositivos plegables de tres pliegues y horizontales, revisa los siguientes conceptos fundamentales de desarrollo adaptable de Android.
Diseños adaptables
Tu IU debe controlar no solo los diferentes tamaños de pantalla, sino también los cambios en tiempo real en la relación de aspecto, como el despliegue y el ingreso a los modos de ventanas múltiples o de ventanas de escritorio. Consulta Acerca de los diseños adaptables para obtener más orientación sobre cómo hacer lo siguiente:
- Diseñar e implementar diseños adaptables
- Ajustar la navegación principal de tu app según el tamaño de la ventana
- Usar clases de tamaño de ventana para adaptar la IU de tu app
- Simplificar la implementación de diseños canónicos, como la lista de detalles, con las APIs de Jetpack
Clases de tamaño de ventana
Los dispositivos plegables, incluidos los dispositivos plegables horizontales y de tres pliegues, pueden cambiar entre clases de tamaño de ventana compactas, medianas y expandidas al instante. Comprender e implementar estas clases garantiza que tu app muestre los componentes de navegación y la densidad de contenido correctos para el estado actual del dispositivo.
En el siguiente ejemplo, se usa la biblioteca adaptable de Material 3 para determinar cuánto
espacio tiene disponible la app. Para ello, primero se invoca la
currentWindowAdaptiveInfo() función y, luego, se usan los
diseños correspondientes para las tres clases de tamaño de ventana:
val adaptiveInfo = currentWindowAdaptiveInfo()
val windowSizeClass = adaptiveInfo.windowSizeClass
when {
windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Expanded
windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -> // Medium
else -> // Compact
}
Para obtener más información, consulta Cómo usar clases de tamaño de ventana.
Calidad de las apps adaptables
Cumplir con el Nivel 2 (App adaptable optimizada) o el Nivel 1 (App adaptable diferenciada) de los lineamientos de calidad de las apps adaptables garantiza que tu app proporcione una experiencia del usuario atractiva en dispositivos de tres pliegues, dispositivos plegables horizontales, y otros dispositivos con pantalla grande. Los lineamientos abarcan verificaciones críticas en varios niveles para pasar de una experiencia adaptable lista a una diferenciada.
Android 16 y versiones posteriores
En el caso de las apps que se orientan a Android 16 (nivel de API 36) y versiones posteriores, el sistema ignora las restricciones de orientación, cambio de tamaño y relación de aspecto en pantallas con un ancho más pequeño >= 600 dp. Las apps ocupan toda la ventana de visualización, independientemente de la relación de aspecto o la orientación preferida del usuario, y ya no se usa el modo de compatibilidad de letterbox.
Consideraciones especiales
Los dispositivos de tres pliegues y los dispositivos plegables horizontales introducen comportamientos de hardware únicos que requieren un manejo específico, en particular, en lo que respecta a los sensores, la vista previa de la cámara y la continuidad de la configuración (retener el estado cuando se pliega, se despliega o se cambia el tamaño).
Vista previa de cámara
Un problema común en los dispositivos plegables horizontales o los cálculos de la relación de aspecto (en situaciones como ventanas múltiples, ventanas de escritorio o pantallas conectadas) es cuando la vista previa de la cámara aparece estirada, lateral, recortada o rotada.
Suposiciones no coincidentes
Este problema suele ocurrir en dispositivos plegables y de pantalla grande porque las apps pueden suponer relaciones fijas entre las funciones de la cámara (como la relación de aspecto y la orientación del sensor) y las funciones del dispositivo (como la orientación del dispositivo y la orientación natural).
Los nuevos factores de forma desafían esta suposición. Un dispositivo plegable puede cambiar el tamaño de la pantalla y la relación de aspecto sin que cambie la rotación del dispositivo. Por ejemplo, desplegar un dispositivo cambia la relación de aspecto, pero si el usuario no rota el dispositivo, su rotación permanece igual. Si una app supone que la relación de aspecto se correlaciona con la rotación del dispositivo, es posible que rote o ajuste incorrectamente la vista previa de la cámara. Lo mismo puede suceder si una app supone que la orientación del sensor de la cámara coincide con la orientación vertical del dispositivo, lo que no siempre es cierto para los dispositivos plegables horizontales.
Solución 1: Jetpack CameraX (la mejor opción)
La solución más sencilla y sólida es usar la biblioteca de Jetpack CameraX. Su
PreviewView elemento de IU está diseñado para controlar automáticamente todas las complejidades de la vista previa:
PreviewViewse ajusta correctamente a la orientación del sensor, la rotación del dispositivo y el ajuste de escala.- Mantiene la relación de aspecto de la imagen de la cámara, por lo general, centrándola y recortándola (FILL_CENTER).
- Puedes establecer el tipo de escala en
FIT_CENTERpara poner en formato letterbox la vista previa si es necesario.
Para obtener más información, consulta Cómo implementar una vista previa en la documentación de CameraX.
Solución 2: CameraViewfinder
Si usas una base de código Camera2 existente, la biblioteca CameraViewfinder (compatible con versiones anteriores hasta el nivel de API 21) es otra solución moderna. Simplifica la visualización de la transmisión de la cámara mediante el uso de un TextureView o SurfaceView y la aplicación de todas las transformaciones necesarias (relación de aspecto, escala y rotación).
Para obtener más información, consulta la entrada de blog Presentación del visor de la cámara y Vista previa de la cámara la guía para desarrolladores.
Solución 3: Implementación manual de Camera2
Si no puedes usar CameraX o CameraViewfinder, debes calcular manualmente la orientación y la relación de aspecto, y asegurarte de que los cálculos se actualicen en cada cambio de configuración:
- Obtén la orientación del sensor de la cámara (por ejemplo, 0, 90, 180, 270 grados) de
CameraCharacteristics. - Obtén la rotación actual de la pantalla del dispositivo (por ejemplo, 0, 90, 180, 270 grados).
- Usa estos dos valores para determinar las transformaciones necesarias para tu
SurfaceViewoTextureView. - Asegúrate de que la relación de aspecto de tu
Surfacede salida coincida con la relación de aspecto de la vista previa de la cámara para evitar la distorsión. - Es posible que la app de cámara se ejecute en una parte de la pantalla, ya sea en el modo de ventanas múltiples o de ventanas de escritorio, o en una pantalla conectada. Por este motivo, no se debe usar el tamaño de la pantalla para determinar las dimensiones del visor de la cámara. En su lugar, usa las métricas de la ventana.
Para obtener más información, consulta la guía para desarrolladores de Vista previa de la cámara y el video Tu app de cámara en diferentes factores de forma.
Solución 4: Realiza acciones básicas de la cámara con un intent
Si no necesitas muchas funciones de la cámara, una solución sencilla es realizar acciones básicas de la cámara, como capturar una foto o un video, con la aplicación de cámara predeterminada del dispositivo. No necesitas integrarla a la biblioteca de la cámara. En su lugar, usa un intent.
Para obtener más información, consulta Intents de la cámara.
Configuración y continuidad
Los dispositivos plegables mejoran la versatilidad de la IU, pero pueden iniciar más cambios de configuración que los dispositivos no plegables. Tu app debe administrar estos cambios de configuración y sus combinaciones, como la rotación del dispositivo, el plegado o el desplegado, y el cambio de tamaño de la ventana en los modos de ventanas múltiples o de escritorio, mientras retiene o restablece el estado de la app. Por ejemplo, las apps deben mantener la siguiente continuidad:
- Estado de la app sin fallar ni causar cambios disruptivos a los usuarios (por ejemplo, cuando se cambian las pantallas o se envía la app a segundo plano)
- Posición de desplazamiento de los campos desplazables
- Texto escrito en los campos de texto y estado del teclado
- Posición de reproducción de contenido multimedia para que la reproducción se reanude en el lugar donde quedó cuando se inició el cambio de configuración
Los cambios de configuración que se activan con frecuencia incluyen screenSize, smallestScreenSize, screenLayout, orientation, density, fontScale, touchscreen y keyboard.
Consulta android:configChanges y Cómo administrar los cambios de configuración. Para obtener información
adicional sobre la administración del estado de la app, consulta Cómo guardar estados de la IU.
Cambios de configuración de densidad
Las pantallas externas e internas de los dispositivos plegables de tres pliegues y horizontales pueden tener diferentes densidades de píxeles. Por lo tanto, administrar el cambio de configuración para density requiere atención adicional. Por lo general, Android reinicia la actividad cuando cambia la densidad de la pantalla, lo que puede provocar la pérdida de datos. Para evitar que el sistema reinicie la actividad, declara el manejo de la densidad en tu manifiesto y administra el cambio de configuración de forma programática en tu app.
Configuración de AndroidManifest.xml
density: Declara que la app controlará el cambio de densidad de la pantalla.- Otros cambios de configuración: También es recomendable declarar otros cambios de configuración que ocurren con frecuencia, por ejemplo,
screenSize,orientation,keyboardHidden,fontScale, etcétera.
Declarar la densidad (y otros cambios de configuración) evita que el sistema reinicie la actividad y, en su lugar, llama a onConfigurationChanged().
Implementación de onConfigurationChanged()
Cuando se produce un cambio de densidad, debes actualizar tus recursos (como volver a cargar mapas de bits o volver a calcular los tamaños de diseño) en la devolución de llamada:
- Verifica que el DPI haya cambiado a
newConfig.densityDpi. - Restablece las vistas personalizadas, los elementos de diseño personalizados, etcétera, a la nueva densidad.
Elementos de recursos para procesar
- Recurso de imagen: Reemplaza los mapas de bits y los elementos de diseño por recursos específicos de la densidad o ajusta la escala directamente.
- Unidad de diseño (conversión de dp a px): Vuelve a calcular el tamaño, el margen y el padding de la vista.
- Tamaño de fuente y texto: Vuelve a aplicar el tamaño de texto de la unidad sp.
- Dibujo personalizado de
View/Canvas: Actualiza los valores basados en píxeles que se usan para dibujarCanvas
Cómo determinar la orientación de la app
Nunca confíes en la rotación física del dispositivo cuando compiles elementos adaptables, ya que se ignorará en los dispositivos con pantalla grande y una app en el modo de ventanas múltiples podría tener una orientación diferente a la del dispositivo. En su lugar, usa Configuration.orientation o WindowMetrics para identificar si tu app se encuentra actualmente en orientación horizontal o vertical según el tamaño de la ventana.
Solución 1: Usa Configuration.orientation
Esta propiedad identifica la orientación en la que se muestra actualmente tu app.
Solución 2: Usa WindowMetrics#getBounds()
Puedes obtener los límites de visualización actuales de la app y verificar su ancho y alto para determinar la orientación.
Si necesitas limitar la orientación de la app en teléfonos (o las pantallas externas de dispositivos plegables), pero no en dispositivos con pantalla grande, consulta Cómo restringir la orientación de las apps en teléfonos.
Posiciones y modos de visualización
Las posiciones y los estados plegables, como la posición de mesa y HALF_OPENED, son
compatibles con los dispositivos plegables verticales y horizontales. Sin embargo, los dispositivos de tres pliegues no admiten la posición de mesa y no se pueden usar HALF_OPENED. En su lugar, los dispositivos de tres pliegues ofrecen una pantalla más grande para una experiencia del usuario única cuando están completamente desplegados.
Para diferenciar tu app en dispositivos plegables que admiten HALF_OPENED, usa las APIs de Jetpack
WindowManager, como FoldingFeature.
Obtén más información sobre las posiciones, los estados y la compatibilidad con la vista previa de la cámara de los dispositivos plegables en las siguientes guías para desarrolladores:
- Más información sobre dispositivos plegables
- Cómo hacer que tu app funcione en dispositivos plegables
Los dispositivos plegables ofrecen experiencias de visualización únicas. El modo de pantalla posterior y el modo Dual Screen te permiten crear funciones de pantalla especiales para dispositivos plegables, como una vista previa de Selfie con cámara posterior y pantallas simultáneas pero diferentes en pantallas internas y externas. Para obtener más información, consulta lo siguiente:
Cómo bloquear la orientación a la orientación natural del sensor
Para casos de uso muy específicos, en particular, apps que necesitan ocupar toda la pantalla sin relación con el estado plegado del dispositivo, el indicador nosensor te permite bloquear la app en la orientación natural del dispositivo. Por ejemplo, en un Pixel Fold, la orientación natural del dispositivo cuando está plegado es vertical, mientras que la orientación natural cuando está desplegado es horizontal. Agregar el indicador nosensor obliga a que la app se bloquee en posición vertical cuando se ejecuta en la pantalla externa y en posición horizontal cuando se ejecuta en la pantalla interna.
<activity
android:name=".MainActivity"
android:screenOrientation="nosensor">
Reasignación de sensores de juegos y RE
En el caso de los juegos y las apps de RE, los datos sin procesar del sensor (como el giroscopio o el acelerómetro) se proporcionan en el sistema de coordenadas fijo del dispositivo. Si el usuario rota el dispositivo para jugar en posición horizontal, los ejes del sensor no rotan con la pantalla, lo que genera controles de juego incorrectos.
Para solucionar este problema, verifica el Display.getRotation() actual y vuelve a asignar los ejes según corresponda:
- Rotación 0: x=x, y=y
- Rotación 90: x=-y, y=x
- Rotación 180: x=-x, y=-y
- Rotación 270: x=y, y=-x
Para los vectores de rotación (que se usan en apps de brújula o RE), usa SensorManager.remapCoordinateSystem() para asignar la dirección de la lente de la cámara o la parte superior de la pantalla a los ejes nuevos según la rotación actual.
Compatibilidad con apps
Las aplicaciones deben seguir los lineamientos de calidad de las apps para garantizar la compatibilidad en todos los factores de forma y las pantallas conectadas. Si una aplicación no puede cumplir con los lineamientos, los fabricantes de dispositivos pueden implementar tratamientos de compatibilidad, aunque esto puede degradar la experiencia del usuario.
Para obtener información adicional, revisa la lista completa de soluciones alternativas de compatibilidad que se proporcionan en la plataforma, en especial, las relacionadas con la vista previa de la cámara, las anulaciones y los cambios en la API de Android 16 que podrían cambiar el comportamiento de tu app.
Para obtener más información sobre la compilación de apps adaptables, consulta los lineamientos de calidad de las apps adaptables.