Resizability en iOS: cuando tu app deja de saber en qué dispositivo corre
Cinco principios de diseño, cada uno aterrizado en código: en la era del redimensionamiento, una app solo se pregunta cuánto espacio tiene. Con configuración de escena, callbacks de geometría, estrategia de dos pasadas, líneas rojas de Info.plist y matriz de prueba.
La resizability es la capacidad de la ventana de una app de ser tomada por el borde y arrastrada libremente a cualquier tamaño, como una ventana de escritorio. El pensamiento de diseño que Apple adjunta a este cambio cabe en una frase: una app ya no se preocupa por saber en qué dispositivo corre, en qué orientación ni sobre qué pantalla. Solo le importa cuánto espacio tiene en ese momento. Tú defines dos comportamientos: cómo se organiza el contenido cuando hay más espacio y cómo cuando hay menos. El sistema aplica esa lógica en todos los dispositivos, todos los tamaños de ventana y todas las posturas de plegado.
Esto no es una actualización de API rutinaria. Es un cambio de carril en el paradigma de disposición desde el nacimiento de iOS. Este artículo descompone el pensamiento de diseño en cinco principios, hace aterrizar cada uno en código UIKit y SwiftUI, y termina con una hoja de ruta de migración y una matriz de prueba que puedes ejecutar tal cual.
Las firmas del texto están contrastadas con el SDK de iOS 27.1 de Xcode 27.1. El comportamiento sigue la documentación de Apple y las sesiones WWDC, cuyas fuentes se listan al final. El cuerpo es una reexposición y una organización técnica, no una traducción de una página concreta.
1. De iOS 26 a 27: cómo el redimensionamiento se volvió el valor por defecto
Antes del pensamiento de diseño, la cronología. Explica por qué la vieja forma de hacer ya no alcanza.
| Etapa | Qué pasó | Qué significa para ti |
|---|---|---|
| iPadOS 15 | Split View / Slide Over / Stage Manager | El iPad empieza a tener tamaños fuera de pantalla completa |
| iPadOS 26 | El iPad entra en la era de ventanas libres | La suposición «iPad = regular» empieza a ceder |
| SDK de iOS 26 | UIRequiresFullScreen queda obsoleto |
Ya no se sale del redimensionamiento con la tecla de pantalla completa |
| SDK de iOS 26 | Las apps de iPhone también se redimensionan en iPad y en espejo en Mac | «Correr en un iPhone» ya no significa compact |
| iOS 27 | El ciclo de vida UIScene es obligatorio para compilaciones con el SDK reciente | Las escenas se vuelven el cimiento |
| iOS 27 | Barra de pestañas, barras de herramientas: los componentes del sistema se adaptan a cualquier relación de aspecto | Los componentes del sistema cargan con el trabajo pesado |
El hilo en una frase: el tamaño de ventana pasó de valor enumerado a valor continuo. Antes tu app enfrentaba 375, 393, 414, 768, 1024. Ahora un dedo agarra el borde de la ventana y arrastra una vez: el ancho puede ser cualquier número entre 320 y el límite de la pantalla. Un diseño escrito para escalones discretos se rompe con seguridad frente a un valor continuo.
2. Principio uno: del «pensamiento de dispositivo» al «pensamiento de espacio»
La mayor parte del conocimiento antiguo de diseño descansa en el pensamiento de dispositivo: esto es un iPhone, está en horizontal, así que se dispone de este modo; esto es un iPad, así que se parte en dos. La resizability pide reemplazar ese pensamiento por completo.
| Pensamiento de dispositivo (viejo) | Pensamiento de espacio (nuevo) | |
|---|---|---|
| Criterio de decisión | Tipo de dispositivo, orientación, tamaño de pantalla | Espacio disponible del contenedor actual |
| Cantidad de diseños | Una versión por dispositivo | Un juego de reglas para todos los espacios |
| Hardware nuevo | Puede exigir cambios de código y una entrega | Se aplica solo, cero cambios |
| Posturas de plegado | Una interfaz más por postura | Una interfaz que se estira con el ancho |
| Olor en el código | if idiom == .pad, isLandscape |
horizontalSizeClass, ancho del contenedor |
La formulación más cruda del pensamiento de espacio viene de la WWDC: no diseñas para cada plataforma ni cada tamaño de ventana. Defines una vez cómo se comporta el contenido cuando hay más sitio y cuando hay menos. El sistema aplica esa lógica a todas las relaciones de aspecto. Girar la pantalla es solo un disparador de esa lógica, de la misma naturaleza que arrastrar una ventana, entrar en Split View o desplegar una pantalla: todo confluye en el mismo punto único: el espacio disponible cambió.
3. Principio dos: las clases de tamaño son la nueva lingua franca
Cuando el pensamiento de dispositivo se retira, ¿qué recoge el testigo? La clase de tamaño. Es el juicio cualitativo que el framework hace del espacio: dos ejes, dos palabras por eje: compact significa apretado, regular significa holgado.
El eje horizontal juzga izquierda y derecha: en compact, el contenido debe apilarse en una columna; solo en regular las columnas, la alineación en paralelo y la barra lateral se vuelven honestas.
El eje vertical juzga arriba y abajo: en compact, el chrome vertical (barra de pestañas, barra de herramientas) ya no cabe, y el sistema levanta una barra de pestañas horizontal a lo alto. En regular, las barras superior e inferior coexisten.
En SwiftUI se lee directo:
@Environment(\.horizontalSizeClass) private var hSize // UserInterfaceSizeClass?
@Environment(\.verticalSizeClass) private var vSize
if hSize == .regular {
// Sitio a izquierda y derecha: columnas / barra lateral / dos filas
} else {
// Apretado a izquierda y derecha: una columna apilada
}
En UIKit, traitCollection.horizontalSizeClass carga con el mismo deber, y con registerForTraitChanges se suscriben los cambios con precisión.
Viene ahora la tabla más importante de este artículo: las clases de tamaño no están en correspondencia biunívoca con el dispositivo ni la orientación:
| Escena | Horizontal | Vertical | Nota |
|---|---|---|---|
| iPhone vertical | compact | regular | La forma por defecto de toda la app |
| iPhone horizontal | compact | compact | Solo unos 320 pt de alto, la barra pasa a lo alto |
| Ventana de iPhone agrandada (iOS 26+) | regular | regular | Cambia en tiempo de ejecución, no al lanzar |
| iPad pantalla completa | regular | regular | Unos 1024 pt de ancho |
| iPad en Split View mitad | regular | regular | Solo unos 507 pt de ancho, sigue siendo regular |
| iPad en Slide Over | compact | compact | Una forma compact sobre iPad |
| Pantalla exterior del Duo | compact | compact | Unos 466 pt de ancho |
| Pantalla interior del Duo desplegada | regular | compact | Cambia en tiempo de ejecución con el plegado |
Lee esta tabla tres veces y emergen dos conclusiones contra-intuitivas: «correr en un iPhone» ya no significa compact (una ventana agrandada es regular), y «correr en un iPad» ya no significa regular (Slide Over es compact). Ni el tipo de dispositivo ni la orientación responden «qué diseño debería usar ahora». Hay que preguntarle a la clase de tamaño, en tiempo de ejecución.
La tabla también corrige una vieja creencia: girar el dispositivo no significa «el dispositivo cambió». Girar conmuta el par (H, V) de (compact, regular) a (compact, compact) y cambia los límites una vez. La estructura de tu código de diseño no se mueve; lo que se mueve es la entrada. En la época en que la orientación era un concepto de diseño, siempre fue una variable de sustitución. El sustituto ya no existe. Solo queda el espacio.
El acantilado de las clases de tamaño: por qué hace falta una segunda pasada
Las clases de tamaño son binarias, y lo bastante gruesas como para «mentir». Mira el acantilado: el iPad a pantalla completa de 1024 pt y la mitad en Split View de 507 pt son ambos (regular, regular): pero uno admite una barra lateral y el otro no. Dos palabras no pueden responder a las preguntas de grado: cuántas columnas, de qué tamaño, conviene acotar el ancho.
El modo maduro es por tanto un relevo de dos pasadas: las clases de tamaño responden la pregunta de dirección (una columna o partido), la estrategia de ingeniería responde la de grado (cuántas columnas, tamaño del héroe, ancho de lectura). La segunda pasada suele escalonar según el ancho medido del contenedor: en pantalla ancha acota el texto a una longitud de línea cómoda, o deduce el número de columnas del tamaño mínimo del contenido. Desde iOS 17, SwiftUI puede medir directamente el tamaño del contenedor con onGeometryChange e inyectarlo en la decisión: no hace falta recurrir a GeometryReader.
4. Principio tres: la funcionalidad no cambia con el tamaño, solo la cantidad visible
Este es un principio de las Human Interface Guidelines fácil de pasar por alto pero imposible de exagerar: cuando cambia la clase de tamaño, el conjunto de funcionalidades permanece idéntico. Lo que cambia es «cuánto se ve de una vez».
En una pantalla ancha, la barra de pestañas se despliega en barra lateral y revela destinos de segundo nivel. En una ventana estrecha, las herramientas de baja prioridad se van al menú de desbordamiento y siguen a un toque. Ocultar es reordenar, no borrar. Si una acción existe en el diseño ancho y desaparece sin rastro en el estrecho, eso no es adaptación, es una funcionalidad ausente. Igualmente, entre vertical y horizontal no debe existir nunca «esta pantalla solo se opera completamente en una orientación»: lo que funciona en vertical debe funcionar de punta a punta en horizontal.
La exigencia implícita para quien diseña el producto: en la arquitectura de información, escribir una prioridad para cada elemento. Compartir y las acciones principales tienen prioridad alta y residen a todo tamaño. Guardar y los ajustes secundarios tienen prioridad baja: residen en ancho, van al desbordamiento en estrecho. El mecanismo Visibility Priority de los componentes del sistema hace exactamente eso.
5. Principio cuatro: los tamaños min / max previenen el solapamiento, no rechazan el redimensionamiento
UIKit permite que una escena declare un tamaño mínimo y uno máximo. Pero la semántica debe quedar clara: estos dos valores existen para evitar que los elementos se tapen unos a otros en tamaños pequeños y se desborden sin control en tamaños grandes. No son una barrera que el usuario deba superar antes de que se le permita arrastrar. Desde el momento en que una ventana puede arrastrarse a cualquier tamaño, tu responsabilidad es mantener el contenido utilizable, legible y sin solapamientos a cualquier tamaño. si un tamaño concreto se rompe inevitablemente, eso dice que tu tamaño mínimo era demasiado codicioso, o que el diseño aún no es realmente adaptativo.
Se declara en la conexión de la escena:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
// Límite inferior: por debajo, los elementos empiezan a solaparse.
// Límite superior: por encima, el diseño se afloja.
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
}
La vieja deuda que lo acompaña: UIRequiresFullScreen está obsoleto, y quien lo conserva queda excluido del redimensionamiento: abandona automáticamente los nuevos tamaños de pantalla. Desde el SDK de iOS 26, las apps no necesitan ni cambiar código ni reenviar para pantallas nuevas; el sistema se adapta solo, siempre que no eches tú mismo el cerrojo a la puerta.
6. Principio cinco: deja que los componentes del sistema hagan el trabajo
La estrategia menos costosa en la era de la resizability es entregar el reordenado a los componentes del sistema. Su trato con relaciones de aspecto arbitrarias es más robusto que cualquier diseño escrito a mano:
Barras de pestañas y barras de herramientas: cuando la ventana se ensancha, los iconos de pestaña se mantienen en la misma línea que sus etiquetas y conservan la barra compacta; cuando se estrecha, las herramientas de baja prioridad fluyen al menú de desbordamiento. En una app de noticias, «Compartir» puede fijarse a todo tamaño y «Guardar para luego» solo desbordar en estrecho: declarado por Visibility Priority, sin una línea de código de diseño.
Barras laterales: desde iPadOS 26, las apps de iPhone también pueden elegir un diseño con barra lateral cuando el espacio lo permite, protegido por
sidebar.isAvailable.NavigationSplitView: desde iOS 26, las columnas aparecen y desaparecen según el sitio; gestionar su visibilidad a mano ya no es necesario.
Materiales de sistema Liquid Glass: en iOS 27, con difusión mejorada y separación de bordes; heredados sin recompilar.
Tu propia interfaz tiene aquí exactamente una tarea: no pelearse con estos ladrillos. Las barras superiores dibujadas a mano deben evitar los controles de cerrar y minimizar en la esquina superior izquierda de la ventana (mediante la guía de diseño con adaptación horizontal de esquinas). Nunca supongas que la barra de pestañas está siempre abajo ni la barra de herramientas siempre arriba: su forma misma cambia con el espacio.
7. UIKit en la práctica: configuración de escena y respuesta a la geometría
Las escenas son el cimiento de la resizability: cada escena gestiona de forma independiente su propia instancia de interfaz y estado, y aporta el contexto «dónde y a qué tamaño está esta interfaz». Desde iOS 27, las compilaciones con el SDK reciente deben adoptar el ciclo de vida UIScene: no es opcional.
Un armazón de delegado de escena para copiar tal cual:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
// 1) Declarar capacidades de tamaño: prevenir el solapamiento, no rechazar el redimensionamiento
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
// 2) Colgar la ventana de la escena; nunca UIWindow(frame: UIScreen.main.bounds)
let window = UIWindow(windowScene: windowScene)
window.rootViewController = AdaptiveRootController()
self.window = window
window.makeKeyAndVisible()
}
// 3) Callback de cambio de geometría: arrastrar, Split View, desplegar, pantalla externa
func windowScene(_ windowScene: UIWindowScene,
didUpdateEffectiveGeometry previous: UIWindowScene.Geometry) {
let geometry = windowScene.effectiveGeometry
let size = geometry.coordinateSpace.bounds.size
// isInteractivelyResizing significa que el usuario aún sostiene el borde.
// El trabajo pesado (reconstrucción de recursos, recálculo de gráficos)
// se hace una vez, cuando el gesto termina: no por cada tamaño intermedio.
if !geometry.isInteractivelyResizing,
size != previous.coordinateSpace.bounds.size {
AssetStore.shared.rebuild(for: size)
}
}
// 4) Preferencia de estilo de los controles de ventana (cerrar / minimizar), iPadOS 26+
func preferredWindowingControlStyle(for scene: UIWindowScene)
-> UIWindowScene.WindowingControlStyle {
.unified
}
}
Tres puntos merecen despliegue:
isInteractivelyResizing es la tabla de salvación del rendimiento al arrastrar. Mientras el usuario arrastra, el sistema reporta geometría de forma continua. Si un juego o una app reconstruye sus recursos de render por cada tamaño intermedio, la frecuencia de cuadros se derrumba en el acto. La postura estándar: mientras se arrastra, solo lo ligero (restricciones, tamaños de letra); al soltar, una vez lo pesado.
Nunca tomes la pantalla ni el tamaño vía UIScreen.main. En espejo y en pantalla externa, la pantalla principal es la respuesta equivocada. Las fuentes correctas son view.window?.windowScene?.screen, la effectiveGeometry de la escena, o los view.bounds locales de la vista.
Evitar los controles de ventana. Desde iPadOS 26, la esquina superior izquierda de la escena lleva los controles de cerrar y minimizar. Las barras superiores dibujadas a mano deben ligarse a containerView.layoutGuide(for: .margins(cornerAdaptation: .horizontal)), o tu primer botón se vuelve intocable.
8. La capa de vistas: tachar tres modos antiguos
El código UIKit adaptativo es, en el fondo, «tres reemplazos»:
| Tachar | Reemplazar por | Por qué |
|---|---|---|
UIScreen.main.bounds |
view.bounds / effectiveGeometry / windowScene?.screen |
En Split View y espejo, la pantalla principal no es tu ventana |
Las ramas userInterfaceIdiom == .pad |
traitCollection.horizontalSizeClass |
El tipo de dispositivo no porta semántica de diseño |
Las ramas interfaceOrientation |
Clase de tamaño + límites locales | La orientación es un resultado del diseño, no su causa |
Tras el cambio, el cambio de rasgo pilota el diseño:
class AdaptiveRootController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Reordenar al cambiar la clase de tamaño; el registro cubre también
// la invalidación de caché que el seguimiento automático no ve
registerForTraitChanges([UITraitHorizontalSizeClass.self,
UITraitVerticalSizeClass.self]) { (vc: Self, _) in
vc.applyLayout()
}
}
private func applyLayout() {
switch (traitCollection.horizontalSizeClass, traitCollection.verticalSizeClass) {
case (.regular, _): useSidebarLayout()
case (.compact, _): useStackedLayout()
default: useStackedLayout()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Cuando el juicio es más fino que una clase de tamaño: tamaño local disponible
fineTune(for: view.bounds.size)
}
}
Fíjate en que viewDidLayoutSubviews / layoutSubviews actúan de forma continua: el cambio de clase de tamaño dispara el «reordenado estructural», el cambio de límites dispara el «ajuste fino». Leer el tamaño una sola vez en onAppear / viewDidLoad y guardarlo produce los primeros valores caducos en cuanto empieza el redimensionamiento.
9. SwiftUI en la práctica: en gran medida automático, reforzado en los puntos clave
Las apps escritas en SwiftUI salen con ventaja en resizability: recompiladas con Xcode 27, el soporte de redimensionamiento llega solo, no hay API nueva que adoptar, y los nuevos materiales Liquid Glass se heredan de paso. Pero «automático» no quiere decir «sin inspección». La caja de herramientas del lado SwiftUI:
@Environment(\.horizontalSizeClass)/verticalSizeClass: equivalente del rasgo UIKit, responde las preguntas de dirección.onGeometryChange(for:of:action:): mide el contenedor, responde las preguntas de grado. Lee sin disparar la toma de espacio codiciosa deGeometryReader, y solo llama a la acción cuando el valor derivado cambia de verdad: un filtro natural para los tamaños intermedios del arrastre.ViewThatFits: el declarativo «toma el primero que quepa», indicado cuando el contenido cambia de disposición según el ancho.containerRelativeFrame(): dimensiona según la proporción del contenedor en vez de puntos absolutos; especialmente útil para zonas que deben extenderse bajo la interfaz del sistema.NavigationSplitView: desde iOS 26, el ancho y la visibilidad de las columnas se adaptan solos; no envuelvas por encima una gestión manual de columnas.
.windowResizability(.contentMinSize): la entrada de SwiftUI para declarar el tamaño mínimo de escena, contraparte desizeRestrictions?.minimumSize.
Un relevo de dos pasadas típico:
struct DashboardView: View {
@Environment(\.horizontalSizeClass) private var hSize
@State private var columnCount = 1
var body: some View {
ScrollView {
MetricGrid(columns: columnCount)
}
// Pasada uno: la clase de tamaño decide una columna o partido
.onChange(of: hSize) { _, new in
usesSidebar = (new == .regular)
}
// Pasada dos: el ancho medido decide el número de columnas,
// cubriendo 507 y 1024 que ambos son "regular"
.onGeometryChange(for: CGFloat.self) { $0.size.width } action: { _, width in
columnCount = AdaptiveWindowLayoutPolicy.tier(for: width).columns
}
}
}
10. Líneas rojas en Info.plist y Launch Screen
Dos líneas rojas viven en la configuración del proyecto. Falla una y detona en el momento del envío:
UIRequiresFullScreendebe tratarse. Obsoleto, y quien lo conserva queda excluido del redimensionamiento. Bórralo; si porta una necesidad real de compatibilidad heredada, usaUIRequiresFullScreenIgnoredStartingWithVersionpara declarar desde qué versión se ignora la clave. Los juegos entran por ello en redimensionamiento discreto: tras cada arrastre completado, conmutan a una nueva configuración de pantalla acorde al tamaño, lo que preserva el render a calidad completa.El Launch Screen es obligatorio. Desde el SDK de iOS 27, una app sin Launch Screen configurado no puede pasar el envío a la App Store (TN3208). En un proyecto SwiftUI, eso suele significar añadir una configuración mínima de pantalla de arranque: no seguir corriendo descalzo.
11. Referencia rápida de antipatrones
Antes de tocar código, pasa la base de código por el peine fino de estos patrones. Cada aparición es una deuda a pagar:
| Antipatrón | Por qué rompe | Reemplazar por |
|---|---|---|
UIScreen.main.bounds |
En Split View / espejo, no es tu ventana | view.bounds locales o geometría de escena |
Ramas UIDevice.current.userInterfaceIdiom |
El tipo de dispositivo no tiene semántica de diseño | horizontalSizeClass |
interfaceOrientation / notificaciones de orientación |
Reportan la postura del dispositivo, no la forma de la ventana | Clase de tamaño + límites locales |
Umbrales caseros tipo size.width > 600 |
Pasan por alto la semántica de rasgos, fallan los estados intermedios del Split View | Estrategia de escalonado de ingeniería + onGeometryChange |
Leer el tamaño una vez en onAppear |
El redimensionamiento es continuo; la caché caduca al instante | Callbacks de rasgo / geometría |
| Diseño ancho solo para el iPad | Un iPad en Slide Over se porta como un teléfono | Lógica ancha y lógica estrecha ambas disparadas por el espacio |
.frame(height: 480) fijo para mapas / héroes |
En ventanas cortas, el texto se desliza fuera de la primera pantalla | Altura relativa al contenedor o adaptativa |
12. Hoja de ruta de migración
Cuatro pasos, ordenados por riesgo y rendimiento:
Fase 1 · Desactivar (primero, bloquea el envío): borrar UIRequiresFullScreen, añadir el Launch Screen, confirmar que el ciclo de vida UIScene está en uso. Estos tres puntos son puertas duras, sin relación con la calidad de diseño; fallar uno atasca directamente en la compilación o la revisión.
Fase 2 · Limpiar antipatrones: con la tabla de la sección 11, reemplazar en toda la base UIScreen.main, las ramas idiom / orientación y los umbrales de ancho caseros. La meta no es «corre»: es unificar la entrada del diseño sobre la semántica del espacio.
Fase 3 · Construir las dos pasadas: para las pantallas lideradas por contenido, establecer la estrategia «la clase de tamaño decide la dirección + el ancho medido decide el grado», y hacer converger cada umbral desnudo a ese lugar único. En pantalla ancha, acotar el ancho del texto: una línea de más de 85 caracteres es un error de legibilidad.
Fase 4 · Sistematizar las pruebas: recorrer la matriz de la sección 13 tamaño por tamaño, y congelar los resultados como puntos de no-regresión.
13. Matriz de prueba
Las pruebas de resizability no se organizan por listas de dispositivos, sino por formas de espacio. Cada forma debe responder: ¿está completa la funcionalidad, se recorta el contenido, es tocable el chrome?
| Forma de espacio | Qué verificar |
|---|---|
| Ancho utilizable más estrecho (cerca de minimumSize) | Solapamiento de elementos, botones principales tocables |
| Ancho de teléfono estándar | Línea base del diseño por defecto |
| Teléfono en horizontal | En vertical compact: barra de pestañas a lo alto, primera pantalla completa |
| Ventana de teléfono agrandada hasta regular | Toman las columnas el relevo, se conserva el estado |
| Split View mitad / Slide Over | Dos comportamientos de espacio en el mismo iPad |
| Proporciones extremas ancha-plana y alta-estrecha | Aguanta la extensión del fondo, el contenido no se desgarra |
| Duo exterior e interior desplegada | Diseño y estado continuos al bascular el pliegue |
| Espejo de iPhone / pantalla externa | Son correctas las consultas de pantalla y tamaño |
Del lado de las herramientas, el Device Hub y las Previsualizaciones de Xcode 27 ofrecen un modo de redimensionamiento de ventana; tirar del borde cambia el tamaño de forma continua. Espejo y pantallas externas se verifican en hardware real.
14. Preguntas frecuentes
¿Por qué mi app de iPhone de repente puede arrastrarse a una ventana más grande?
No es un error: comportamiento nuevo desde el SDK de iOS 26. Las apps de iPhone que corren en iPad y en el espejo de iPhone en Mac tienen ventanas libremente redimensionables. La señal de diseño correspondiente es la clase de tamaño horizontal, que bascula de compact a regular. El viejo código if idiom == .phone produce el diseño equivocado en tales ventanas: pregúntale a la clase de tamaño.
¿Bastan las clases de tamaño? ¿Por qué medir también el ancho?
No bastan, y el acantilado es real. El iPad a pantalla completa y la mitad en Split View son ambos (regular, regular), pero sus anchos difieren en un factor de dos: uno admite barra lateral y el otro no. Las clases de tamaño deciden la dirección (una columna o partido), el ancho medido decide el grado (cuántas columnas, de qué tamaño). Ambas son un relevo, no una elección.
Si declaro minimumSize, ¿los usuarios ya no pueden arrastrar más pequeño?
minimumSize es el límite por debajo del cual tu contenido empezaría a enredarse; los usuarios no pueden arrastrar más allá. Es un mecanismo de prevención de solapamientos, no un portal de funcionalidad contra el redimensionamiento. Lo que debes es usabilidad a todo tamaño entre minimumSize y maximumSize. Si un tamaño falla, la adaptación está inacabada: no es razón para subir el mínimo.
¿Qué pasa si borro UIRequiresFullScreen?
La app entra en el redimensionamiento de ventanas, lo esperado por defecto desde iOS 26+. Para compatibilidad heredada puedes usar UIRequiresFullScreenIgnoredStartingWithVersion y declarar la versión desde la que se ignora; los juegos entran en redimensionamiento discreto y conmutan tras cada arrastre a una configuración de pantalla acorde, lo que preserva mejor la calidad de render.
¿Qué debe hacer realmente una app de SwiftUI?
Recompilar, y el soporte de redimensionamiento ya está; no hay API nueva que adoptar. Inspecciona más bien: código que se apoya en suposiciones de la era de UIScreen; juicios de tamaño que solo usan clases de tamaño sin refuerzo de medición; componentes de marco fijo que se desgarran en proporciones extremas. El framework se ocupa de lo macro. El componente que se desgarra suele ser el que tú mismo clavaste.
Fuentes y lecturas adicionales
Fuentes oficiales: la sesión WWDC25 282 «Make your UIKit app more flexible», la sesión WWDC26 278 «Modernize your UIKit app», las secciones Layout y Designing for iPhone Duo de las Human Interface Guidelines, la documentación de UISceneSizeRestrictions y UIWindowScene.Geometry, y las notas técnicas TN3192: migración desde la clave UIRequiresFullScreen obsoleta y TN3208: requisitos del Launch Screen.
Lecturas adicionales en este sitio: para ver el mismo pensamiento aterrizando de punta a punta en un dispositivo concreto, lee Diseñar para el iPhone Duo, del diseño al código. Para la otra cara: los datos también deben contraerse con el espacio, mira la guía de la línea base personal. Las demás preguntas de producto y adaptación están en las preguntas frecuentes.
Seguir leyendo
Prueba estas ideas en Stress HRV
Descargar en App StoreEstas notas comparten pensamiento de producto para bienestar. No son consejo médico.