wandres.dev
UI ADAPTATIVA · plegables, tablets y XR

El fin de una app solo de móvil

Durante quince años el desarrollo de Android descansó sobre una suposición que nadie escribía porque nadie la discutía: una ventana vertical, a pantalla completa, de tamaño constante. Esa suposición dejó de ser cierta hace tiempo y en Android 16 dejó de ser tolerada. Esta lección reconstruye cómo se rompió el modelo del teléfono único, detalla qué restricciones del manifiesto han pasado a ignorarse en pantallas grandes, disecciona la anatomía de una aplicación rígida y propone el reemplazo conceptual que sostiene el resto del nivel: dejar de razonar sobre dispositivos y empezar a razonar sobre ventanas.

⏱ 18 min

Hay una premisa que ha gobernado en silencio casi todo el código de interfaz escrito para Android: mi aplicación ocupará la pantalla entera, esa pantalla será más alta que ancha, y su tamaño no cambiará mientras la aplicación esté viva. Nunca se declaró porque no hacía falta declararla; era el mundo. Sobre ella se construyeron los diseños de una sola columna, los dp codificados a mano, la navegación inferior universal y esa línea de manifiesto —android:screenOrientation="portrait"— que millones de proyectos copiaron sin pensar. El problema no es que la premisa haya envejecido, sino que ya no describe ni la mitad del parque de dispositivos: tablets, plegables, escritorios con ventanas libres, pantallas externas conectadas por cable, automóviles y visores. Android 16 dio el paso que faltaba y convirtió una recomendación de años en una imposición del sistema: en pantallas grandes, las declaraciones de rigidez del manifiesto simplemente se ignoran. Esta lección explica qué se rompió, qué cambió exactamente y con qué modelo mental hay que sustituirlo.

🎯 Al terminar esta lección sabrás
  • Describir la composición real del parque de dispositivos Android y por qué invalida el diseño de columna única fija.
  • Enumerar con precisión qué restricciones del manifiesto han dejado de tener efecto y bajo qué condiciones.
  • Reconocer en código propio los síntomas de una aplicación rígida antes de que el sistema los castigue.
  • Sustituir el razonamiento por tipo de dispositivo por el razonamiento por ventana disponible.

El parque ya no cabe en un rectángulo vertical

La forma más limpia de entender el cambio es dejar de contar dispositivos y empezar a contar modos de presentación, porque un mismo aparato puede ofrecer varios y cada uno impone una geometría distinta. Un plegable moderno es un teléfono estrecho cerrado y una tablet cuadrada abierto, y transita entre ambos estados en mitad de una sesión. Una tablet con teclado es un portátil. Un teléfono conectado a un monitor externo se convierte en un escritorio con ventanas superpuestas y redimensionables. Un Chromebook ejecuta la misma aplicación dentro de una ventana que el usuario arrastra por una esquina con el ratón.

El recuento por modos, además, deja claro que ni siquiera hay una correspondencia estable entre aparato y geometría. Un mismo teléfono atraviesa en un día el modo a pantalla completa vertical, el horizontal, la pantalla dividida, la ventana flotante sobre otra aplicación y, si se conecta a un monitor, el escritorio con ventanas libres. Contar dispositivos sugiere que las pantallas grandes son una minoría; contar modos de presentación revela que la geometría inesperada le ocurre, varias veces al día, a prácticamente todos los usuarios.

Ese último caso es el que más desconcierto produce, porque rompe la suposición más profunda de todas: no la de la orientación, sino la de la estabilidad. En un escritorio con ventanas libres el tamaño de la ventana no es un dato de arranque sino una señal continua que cambia decenas de veces por segundo mientras el usuario arrastra. Una aplicación que consulta su anchura una vez en onCreate y guarda el resultado ya está rota antes de terminar de dibujarse.

Hay un segundo modo de presentación que se subestima aún más porque no requiere hardware especial: la multiventana. Cualquier teléfono moderno permite partir la pantalla entre dos aplicaciones, y en esa situación tu ventana mide la mitad de alto o la mitad de ancho de lo que asumías, sin que haya cambiado nada del dispositivo. La multiventana lleva años disponible y sigue siendo el escenario donde más aplicaciones se rompen, precisamente porque no viene acompañada de la señal visual de estoy en una tablet que empujaría a alguien a probarla.

Conviene añadir una observación sobre la distribución del uso que suele sorprender: las sesiones en pantallas grandes no se reparten de forma uniforme a lo largo del día. Se concentran en las franjas de consumo prolongado y de mayor intención de compra, precisamente donde la aplicación se juega la conversión y la retención. Tratar la pantalla grande como un caso marginal equivale a degradar deliberadamente el escenario en el que el usuario está más dispuesto a comprometerse, y a hacerlo justo cuando está comparando alternativas con más calma que nunca.

A esa lista se añaden dos superficies que ya no son experimentales y que llevan el mismo razonamiento al extremo: los sistemas de información del automóvil, con una geometría horizontal muy ancha y restricciones de interacción severas, y los visores de realidad extendida, donde la ventana flota en el espacio y el usuario puede redimensionarla a voluntad sin límite superior práctico. Ninguna de las dos exige trabajo específico para empezar, pero ambas castigan sin piedad cualquier suposición sobre proporción o tamaño máximo.

📐

Continuo, no categorías

Entre el teléfono estrecho y el escritorio no hay tres tallas sino un rango continuo de anchuras. Cualquier diseño que solo contemple dos extremos falla en el centro.

🔀

Mutable, no fijo

El tamaño de la ventana cambia durante la sesión: al plegar, al girar, al arrastrar, al dividir la pantalla, al conectar un monitor. Es una señal, no una constante.

Qué cambió exactamente en Android 16

Hasta ahora, una aplicación podía protegerse del mundo declarando en el manifiesto que solo funcionaba en vertical, que no admitía redimensionado o que su relación de aspecto máxima era tal. El sistema honraba esas declaraciones y, cuando no podía, encerraba la aplicación en un rectángulo con bandas negras. Android 16 retira esa protección en el escenario donde más daño hacía.

La regla, formulada con precisión, tiene tres condiciones que deben cumplirse a la vez. Primera, que la aplicación apunte al nivel de API correspondiente a Android 16 o superior. Segunda, que la ventana se muestre en una pantalla cuya dimensión menor alcance los 600dp, que es el umbral que separa un teléfono de todo lo demás. Y tercera, que se trate de una actividad de interfaz ordinaria y no de una excepción reconocida por el sistema. Cumplidas las tres, las declaraciones android:screenOrientation, android:resizableActivity y los límites de relación de aspecto dejan de tener efecto, junto con las llamadas equivalentes en tiempo de ejecución que fijan la orientación.

flowchart TD
A[La app declara orientacion fija o no redimensionable] --> B[El sistema evalua el destino]
B --> C[Pantalla con dimension menor bajo 600dp]
B --> D[Pantalla con dimension menor de 600dp o mas]
C --> E[Se respeta la declaracion del manifiesto]
D --> F[Las restricciones se ignoran]
F --> G[La ventana cambia de tamano y de proporcion]
G --> H[App adaptativa usa todo el espacio]
G --> I[App rigida cae en modo de compatibilidad]
style F fill:#f38ba8,color:#11111b
style H fill:#a6e3a1,color:#11111b

Dicho de otro modo: estas tres líneas siguen estando permitidas, siguen compilando y siguen instalándose, y en el escenario que más importa ya no hacen nada.

<!-- En pantallas grandes con el nivel de API objetivo actual, esto se ignora -->
<activity
    android:name=".MainActivity"
    android:screenOrientation="portrait"
    android:resizableActivity="false"
    android:maxAspectRatio="1.86" />

Las excepciones reconocidas son pocas y conviene conocerlas para no confundirse al probar. La más relevante afecta a las aplicaciones declaradas como juego mediante la categoría correspondiente en el manifiesto, que conservan la capacidad de fijar orientación por razones evidentes de diseño de experiencia. También quedan fuera del alcance las ventanas que el propio sistema gestiona de forma especial y, obviamente, todo lo que se muestre en una pantalla por debajo del umbral. Fuera de esos casos, la regla se aplica sin matices.

Existe una válvula de escape y conviene entenderla bien para no apoyarse en ella. El sistema admite una propiedad de manifiesto que permite conservar temporalmente el comportamiento restringido, pensada para dar margen a las aplicaciones con más deuda acumulada. Es una prórroga con fecha de caducidad anunciada: está previsto que deje de surtir efecto en la siguiente vuelta del ciclo anual, cuando el nivel de API objetivo obligatorio avance otro escalón. Usarla es legítimo como plan de transición y suicida como plan definitivo.

⚠️
El modo de compatibilidad no es una red de seguridad

Cuando una aplicación rígida acaba en una ventana que no espera, el sistema aplica un modo de compatibilidad: bandas laterales, escalado, congelación de la relación de aspecto. El resultado es una aplicación que ocupa un tercio de una pantalla de treinta centímetros mientras el resto es negro, con el texto ampliado por interpolación y los objetivos táctiles desplazados. No es una degradación elegante sino una señal visible para el usuario de que esta aplicación no está mantenida. Y el sistema, además, la etiqueta como tal en varios puntos de la experiencia.

La anatomía de una aplicación rígida

La rigidez rara vez vive en un solo sitio; se acumula en capas que se refuerzan entre sí. Reconocerlas es el primer trabajo de auditoría del nivel.

La primera capa es declarativa y vive en el manifiesto: orientación fija, redimensionado desactivado, relación de aspecto limitada. Es la más visible y la más fácil de quitar, y por eso mismo la más engañosa: borrar esas líneas no vuelve adaptativa la aplicación, solo retira el disfraz que ocultaba el problema real.

La segunda es estructural y vive en el árbol de composición. Una jerarquía construida como una columna única con un desplazamiento vertical no tiene nada que ofrecer cuando recibe mil doscientos puntos de ancho: los estira, y el resultado son líneas de texto de treinta palabras que ningún ojo puede seguir y una franja de contenido flotando en un océano vacío. La medida correcta de una línea de texto ronda las sesenta o setenta unidades tipográficas, y ese límite no depende del dispositivo sino de la fisiología de la lectura.

La tercera es de estado, y es la que produce los defectos más caros porque solo aparece en movimiento. Una aplicación que pierde la posición del desplazamiento, el texto a medio escribir o el fotograma del vídeo cada vez que el usuario gira o pliega el dispositivo no tiene un problema de diseño sino de gestión del ciclo de vida. El cambio de geometría es un cambio de configuración, y todo lo que no esté en un contenedor que sobreviva al cambio se pierde.

Conviene insistir en que esta capa no se arregla con un ancho máximo y ya está. Un contenido limitado y centrado en una pantalla ancha es correcto pero conservador: aprovecha la legibilidad y desaprovecha el espacio. La respuesta completa exige decidir qué contenido secundario merece estar visible a la vez que el principal, y esa es una pregunta de producto que ningún ajuste de disposición responde por su cuenta.

La cuarta es de suposición implícita, la más difícil de detectar porque no aparece en ningún archivo de recursos. Es el código que consulta las métricas de la pantalla física en lugar de las de la ventana, el que decide si mostrar la navegación lateral preguntando por una bandera booleana llamada esTablet calculada en el arranque, o el que asume que la anchura disponible es la anchura del dispositivo. En un escritorio con ventanas libres, la pantalla mide dos mil puntos y la ventana de tu aplicación puede medir cuatrocientos.

// Sintoma cuatro: preguntar por el dispositivo en lugar de por la ventana
val esTablet = resources.configuration.smallestScreenWidthDp >= 600   // frágil
if (esTablet) mostrarPanelLateral() else mostrarNavegacionInferior()

Esa línea sigue compilando y sigue devolviendo un valor. Lo que ya no hace es responder a la pregunta correcta, porque la dimensión menor de la pantalla no dice nada sobre el espacio que el gestor de ventanas te ha concedido en este instante.

Hay una quinta capa que merece mención aparte porque suele considerarse ya resuelta: la de los recursos alternativos por calificador de ancho. Durante años, la respuesta canónica a las tablets fue duplicar los archivos de disposición en una carpeta con el sufijo correspondiente al ancho mínimo. Ese mecanismo sigue funcionando y sigue siendo válido para dimensiones y para recursos, pero como estrategia estructural tiene un defecto grave: bifurca el árbol en dos copias que divergen con el tiempo, no cubre el continuo entre ambas y no reacciona a un cambio en caliente sin recrear. En un mundo declarativo, la decisión estructural pertenece al código, donde se puede leer, probar y componer, no al sistema de selección de recursos.

Conviene terminar el inventario con una observación sobre el orden de reparación. Estas cinco capas no se corrigen en paralelo ni en el orden en que se descubren. La primera en tocarse debe ser la de estado, porque sin continuidad cualquier mejora visual queda anulada en el primer giro; después la de suposición implícita, porque envenena todas las decisiones posteriores; y solo entonces la estructural, que es la más visible y por eso la que todo el mundo quiere hacer primero. La declarativa se retira al final, cuando las otras ya sostienen el peso.

De dispositivos a ventanas

El reemplazo conceptual cabe en una frase: tu aplicación no se ejecuta en un dispositivo, se ejecuta en una ventana, y esa ventana es un contrato renegociable que el sistema te ofrece y te retira a voluntad. Todo lo que se deduzca del dispositivo es una inferencia; todo lo que se mida de la ventana es un hecho.

Ese desplazamiento tiene una traducción sintáctica muy concreta y muy fácil de auditar. Una aplicación que razona sobre dispositivos hace preguntas de identidad, del tipo esto es una tablet, y guarda la respuesta. Una que razona sobre ventanas hace preguntas de capacidad, del tipo hay sitio para dos columnas, y las vuelve a hacer cada vez que algo cambia. La primera forma produce un booleano que envejece; la segunda produce un estado observable que siempre es cierto.

De ahí se derivan cuatro consecuencias operativas que estructuran las lecciones siguientes. La disponibilidad de espacio se mide, nunca se supone, y se mide sobre la ventana. El resultado de esa medida se traduce en unas pocas categorías estables que sirven para decidir estructura, no para identificar hardware. Las estructuras que se eligen no se inventan una por pantalla, sino que salen de un catálogo pequeño de disposiciones canónicas con comportamiento probado. Y la continuidad del estado a través de los cambios de geometría deja de ser un detalle de robustez para convertirse en un requisito funcional de primer orden.

💡
Una prueba de una sola frase para detectar la suposicion oculta

Recorre tu código buscando cualquier lugar donde el resultado de una medida se guarde en una variable que no se vuelva a calcular. Si esa variable influye en lo que se dibuja, ya tienes un defecto latente: has convertido una señal continua en una constante. La versión adaptativa de esa misma línea no guarda el valor, lo observa.

Hay una consecuencia más, de orden cultural, que conviene explicitar. Diseñar para un continuo obliga a decidir qué es lo esencial de cada pantalla y qué es acompañamiento, porque en la ventana estrecha solo cabe lo primero y en la ancha hay que saber con qué llenar lo segundo sin inventar ruido. Ese ejercicio de jerarquización mejora la versión de teléfono también, y ese es el argumento que más a menudo convence a un equipo escéptico: el trabajo adaptativo no es un impuesto que se paga por las tablets, es una revisión de la arquitectura de información que beneficia a todas las tallas.

📏

Se mide, no se supone

El espacio disponible se obtiene de las métricas de la ventana en cada instante. Cualquier inferencia a partir del modelo, de la densidad o de la pantalla física es una conjetura.

🧭

Estructura, no identidad

La medida se traduce en categorías que deciden disposición. Nunca en etiquetas que decidan qué es el aparato ni qué puede hacer el usuario con él.

🧱

Patrones, no invenciones

Las disposiciones salen de un catálogo pequeño y probado. Inventar una por pantalla multiplica el coste y pierde el comportamiento heredado.

🔗

Continuidad, no reinicio

Todo cambio de geometría ocurre en mitad de una tarea. Conservar el estado a través de él es un requisito funcional, no un pulido posterior.

Lo que Android 16 hace en realidad es retirar una subvencion

Vale la pena leer este cambio con precisión histórica, porque la interpretación habitual —Google obliga a soportar tablets— es a la vez cierta y superficial, y no explica por qué llegó ahora ni por qué llegó así. Lo que existía hasta este punto era una subvención implícita: el sistema absorbía el coste de la rigidez de las aplicaciones mediante capas de compatibilidad cada vez más elaboradas, y ese coste lo pagaba el usuario en forma de bandas negras, de escalados borrosos y de superficies desaprovechadas. Cada año que la subvención se mantenía, el incentivo de cada equipo individual era claro y racional: no invertir, porque el sistema seguiría cubriendo el hueco y porque las métricas de pantalla grande eran pequeñas —pequeñas, entre otras cosas, porque la experiencia era mala, en un bucle que se alimentaba a sí mismo. Ese equilibrio es un caso de manual de fallo de coordinación: ningún actor individual gana moviéndose primero, y por tanto nadie se mueve, aunque todos ganarían si se movieran a la vez. La única forma conocida de romper un equilibrio así es que el árbitro cambie las reglas de golpe y para todos al mismo tiempo, que es exactamente lo que significa ignorar las declaraciones del manifiesto en lugar de recomendar que no se usen. Obsérvese la elegancia del mecanismo elegido: no se rompen las aplicaciones antiguas, no se retira ninguna API, no se exige reescribir nada. Se cambia el destinatario del coste. A partir de ahora, la rigidez la paga quien la escribe, en forma de una experiencia visiblemente peor que la del competidor que sí invirtió, en la misma pantalla y delante del mismo usuario. Y una vez que el coste está bien asignado, la corrección deja de necesitar exhortaciones morales sobre buenas prácticas y se convierte en lo que siempre debió ser: una decisión de producto con un retorno medible. Entender esto cambia también la conversación interna en un equipo. La pregunta deja de ser cuántos usuarios tienen tablet —una pregunta cuya respuesta siempre invita a posponer— y pasa a ser cuánto vale la sesión que ahora mismo estamos degradando, en qué franja horaria ocurre y frente a qué alternativa se compara el usuario mientras la sufre.

⚔️ Auditoria de rigidez de tu proyecto
  1. Busca en todos los manifiestos del proyecto las declaraciones de orientación, redimensionado y relación de aspecto. Anota cuántas hay, quién las escribió y qué problema pretendían resolver.
  2. Localiza cada punto del código donde se consulten métricas de pantalla o banderas del tipo esTablet. Clasifica cada uno según si la pregunta correcta era sobre el dispositivo o sobre la ventana.
  3. Ejecuta la aplicación en un emulador redimensionable, arrastra el borde desde el ancho mínimo hasta el máximo sin soltar y graba el resultado. Cuenta los defectos visibles.
  4. Con la aplicación en una pantalla ancha, mide la longitud de línea de tu pantalla de contenido más larga en número de caracteres. Si pasa de setenta, ya tienes tu primer trabajo.
  5. Escribe media página justificando la inversión adaptativa en términos de sesiones degradadas y no de porcentaje de dispositivos. Es el documento que necesitarás para conseguir el tiempo.