Resizability no iOS: quando seu app deixa de saber em qual dispositivo roda
Cinco princípios de design, cada um aterrissado em código: na era do redimensionamento, um app só se pergunta quanto espaço tem. Com configuração de cena, callbacks de geometria, estratégia de duas passadas, linhas vermelhas do Info.plist e matriz de teste.
A resizability é a capacidade da janela de um app de ser pega pela borda e arrastada livremente para qualquer tamanho, como uma janela de desktop. O pensamento de design que a Apple acompanha essa mudança cabe em uma frase: um app não se preocupa mais em saber em qual dispositivo roda, em qual orientação, em qual tela. Só lhe importa quanto espaço tem neste instante. Você define dois comportamentos: como o conteúdo se organiza quando há mais espaço e como quando há menos. O sistema aplica essa lógica em todos os dispositivos, todos os tamanhos de janela e todas as posturas de dobradiça.
Isso não é uma atualização de API corriqueira. É uma troca de faixa no paradigma de layout desde o nascimento do iOS. Este artigo decompõe o pensamento de design em cinco princípios, faz cada um aterrissar em código UIKit e SwiftUI, e termina com um roteiro de migração e uma matriz de teste que você pode executar do jeito que está.
As assinaturas no texto foram conferidas com o SDK do iOS 27.1 no Xcode 27.1. O comportamento segue a documentação da Apple e as sessões da WWDC, cujas fontes estão listadas no final. O corpo é uma reexposição e uma organização técnica, não uma tradução de uma página específica.
1. Do iOS 26 ao 27: como o redimensionamento virou o padrão
Antes do pensamento de design, a linha do tempo. Ela explica por que o jeito antigo de fazer já não basta.
| Etapa | O que aconteceu | O que significa para você |
|---|---|---|
| iPadOS 15 | Split View / Slide Over / Stage Manager | O iPad passa a ter tamanhos fora da tela cheia |
| iPadOS 26 | O iPad entra na era das janelas livres | A suposição «iPad = regular» começa a balançar |
| SDK do iOS 26 | UIRequiresFullScreen fica obsoleto |
Não dá mais para sair do redimensionamento pelo botão de tela cheia |
| SDK do iOS 26 | Apps de iPhone também redimensionam no iPad e no espelhamento no Mac | «Rodar num iPhone» já não significa compact |
| iOS 27 | O ciclo de vida UIScene é obrigatório para builds com SDK recente | As cenas passam a ser a base |
| iOS 27 | Barra de abas, barras de ferramentas: os componentes do sistema se adaptam a qualquer proporção | Os componentes do sistema fazem o trabalho pesado |
O fio em uma frase: o tamanho da janela passou de valor enumerado para valor contínuo. Antes seu app encarava 375, 393, 414, 768, 1024. Agora um dedo pega a borda da janela e arrasta uma vez: a largura pode ser qualquer número entre 320 e o limite da tela. Um layout escrito para degraus discretos quebra com certeza diante de um valor contínuo.
2. Princípio um: do «pensamento de dispositivo» ao «pensamento de espaço»
A maior parte do conhecimento antigo de layout repousa sobre o pensamento de dispositivo: isto é um iPhone, está em paisagem, então dispõe-se assim; isto é um iPad, então divide-se em dois. A resizability pede para trocar esse pensamento por completo.
| Pensamento de dispositivo (velho) | Pensamento de espaço (novo) | |
|---|---|---|
| Critério de decisão | Tipo de dispositivo, orientação, tamanho de tela | Espaço disponível do contêiner atual |
| Quantidade de layouts | Uma versão por dispositivo | Um único conjunto de regras para todos os espaços |
| Hardware novo | Pode exigir mudança de código e uma entrega | Aplica-se sozinho, zero mudanças |
| Posturas de dobradiça | Uma interface a mais por postura | Uma interface que se alonga com a largura |
| Sinal de alerta no código | if idiom == .pad, isLandscape |
horizontalSizeClass, largura do contêiner |
A formulação mais crua do pensamento de espaço vem da WWDC: você não desenha para cada plataforma nem para cada tamanho de janela. Você define uma vez como o conteúdo se comporta quando há mais lugar e quando há menos. O sistema aplica essa lógica em todas as proporções. Girar a tela é apenas um disparador dessa lógica, da mesma natureza que arrastar uma janela, entrar em Split View ou desdobrar uma tela: tudo conflui para o mesmo ponto único: o espaço disponível mudou.
3. Princípio dois: as classes de tamanho são a nova língua franca
Quando o pensamento de dispositivo se retira, quem assume o bastão? A classe de tamanho. É o julgamento qualitativo que o framework faz do espaço: dois eixos, duas palavras por eixo: compact significa apertado, regular significa folgado.
O eixo horizontal julga esquerda e direita: em compact, o conteúdo deve empilhar em uma coluna; só em regular as colunas, o pareamento e a barra lateral ficam honestos.
O eixo vertical julga acima e abaixo: em compact, o chrome vertical (barra de abas, barra de ferramentas) não cabe mais, e o sistema levanta uma barra de abas horizontal na vertical. Em regular, as barras de cima e de baixo coexistem.
Em SwiftUI a leitura é direta:
@Environment(\.horizontalSizeClass) private var hSize // UserInterfaceSizeClass?
@Environment(\.verticalSizeClass) private var vSize
if hSize == .regular {
// Lugar à esquerda e à direita: colunas / barra lateral / duas fileiras
} else {
// Apertado à esquerda e à direita: uma coluna empilhada
}
Em UIKit, traitCollection.horizontalSizeClass carrega o mesmo dever, e com registerForTraitChanges é possível assinar as mudanças com precisão.
Vem agora a tabela mais importante deste artigo: as classes de tamanho não estão em correspondência biunívoca com o dispositivo nem com a orientação:
| Cena | Horizontal | Vertical | Nota |
|---|---|---|---|
| iPhone retrato | compact | regular | A forma padrão de todo o app |
| iPhone paisagem | compact | compact | Só uns 320 pt de altura, a barra passa para a vertical |
| Janela do iPhone ampliada (iOS 26+) | regular | regular | Muda em tempo de execução, não no lançamento |
| iPad tela cheia | regular | regular | Cerca de 1024 pt de largura |
| iPad em Split View pela metade | regular | regular | Só uns 507 pt de largura, ainda regular |
| iPad em Slide Over | compact | compact | Uma forma compact no iPad |
| Tela externa do Duo | compact | compact | Cerca de 466 pt de largura |
| Tela interna do Duo desdobrada | regular | compact | Muda em tempo de execução com a dobradiça |
Leia esta tabela três vezes e duas conclusões contra-intuitivas emergem: «rodar num iPhone» já não significa compact (uma janela ampliada é regular), e «rodar num iPad» já não significa regular (Slide Over é compact). Nem o tipo de dispositivo nem a orientação respondem «que layout devo usar agora». É preciso perguntar à classe de tamanho, em tempo de execução.
A tabela também corrige uma crença antiga: girar o dispositivo não significa «o dispositivo mudou». Girar comuta o par (H, V) de (compact, regular) para (compact, compact) e muda os limites uma vez. A estrutura do seu código de layout não se move; o que se move é a entrada. Na época em que a orientação era um conceito de layout, ela sempre foi uma variável de substituição. A substituição acabou. Só resta o espaço.
O penhasco das classes de tamanho: por que ainda precisa de uma segunda passada
As classes de tamanho são binárias, e grossas o bastante para «mentir». Veja o penhasco: o iPad em tela cheia com 1024 pt e a metade em Split View com 507 pt são ambos (regular, regular): mas um cabe uma barra lateral, o outro não. Duas palavras não conseguem responder às perguntas de grau: quantas colunas, de que tamanho, limitar a largura ou não.
O modo maduro é, portanto, um revezamento de duas passadas: as classes de tamanho respondem à pergunta de direção (uma coluna ou dividido), a estratégia de engenharia responde à pergunta de grau (quantas colunas, tamanho do herói, largura de leitura). A segunda passada costuma escalonar pela largura medida do contêiner: em tela larga, limita o texto a um comprimento de linha confortável, ou deduz o número de colunas do tamanho mínimo do conteúdo. Desde o iOS 17, o SwiftUI consegue medir direto o tamanho do contêiner com onGeometryChange e injetá-lo na decisão: não precisa recorrer ao GeometryReader.
4. Princípio três: a funcionalidade não muda com o tamanho, muda apenas a quantidade visível
Este é um princípio das Human Interface Guidelines fácil de deixar passar e impossível de superestimar: quando a classe de tamanho muda, o conjunto de funcionalidades permanece idêntico. O que muda é «quanto se vê de uma vez».
Em uma tela larga, a barra de abas se desdobra em barra lateral e revela destinos de segundo nível. Em uma janela estreita, as ferramentas de baixa prioridade vão para o menu de excesso e continuam a um toque. Esconder é rearranjar, não apagar. Se uma ação existe no layout largo e desaparece sem rastro no estreito, isso não é adaptação, é funcionalidade ausente. Da mesma forma, entre retrato e paisagem nunca deve existir «esta tela só opera completamente em uma orientação»: o que funciona em retrato tem de funcionar de ponta a ponta em paisagem.
A exigência implícita para quem desenha o produto: na arquitetura da informação, escreva uma prioridade para cada elemento. Compartilhar e ações principais têm prioridade alta e residem em qualquer tamanho. Salvar e ajustes secundários têm prioridade baixa: residem no largo, vão para o excesso no estreito. O mecanismo Visibility Priority dos componentes do sistema faz exatamente isso.
5. Princípio quatro: os tamanhos min / max previnem sobreposição, não recusam o redimensionamento
O UIKit permite que uma cena declare um tamanho mínimo e um máximo. Mas a semântica precisa ficar clara: esses dois valores existem para evitar que elementos se cubram uns aos outros em tamanhos pequenos e se desmanchem em tamanhos grandes. Eles não são uma barreira que o usuário precisa superar antes de ter permissão para arrastar. A partir do momento em que uma janela pode ser arrastada para qualquer tamanho, sua responsabilidade é manter o conteúdo utilizável, legível e sem sobreposições em qualquer tamanho. Se um tamanho específico quebra inevitavelmente, então seu tamanho mínimo foi ganancioso demais, ou o layout ainda não é realmente adaptativo.
Declara-se na conexão da cena:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
// Limite inferior: abaixo dele, os elementos começam a se sobrepor.
// Limite superior: acima dele, o layout afrouxa.
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
}
A dívida antiga que acompanha: UIRequiresFullScreen está obsoleto, e quem o mantém fica excluído do redimensionamento: abandona automaticamente os novos tamanhos de tela. Desde o SDK do iOS 26, os apps não precisam nem mudar código nem reenviar para telas novas; o sistema se adapta sozinho, desde que você não tranque a porta por conta própria.
6. Princípio cinco: deixe os componentes do sistema fazerem o trabalho
A estratégia menos custosa na era da resizability é entregar o rearranjo aos componentes do sistema. O trato deles com proporções arbitrárias é mais robusto que qualquer layout escrito à mão:
Barras de abas e barras de ferramentas: quando a janela se alarga, os ícones das abas ficam na mesma linha que seus rótulos e mantêm a barra compacta; quando se estreita, as ferramentas de baixa prioridade escorrem para o menu de excesso. Num app de notícias, «Compartilhar» pode ser fixado em qualquer tamanho e «Salvar para depois» só transborda no estreito: declarado por Visibility Priority, sem uma linha de código de layout.
Barras laterais: desde o iPadOS 26, os apps de iPhone também podem escolher um layout com barra lateral quando o espaço permite, protegido por
sidebar.isAvailable.NavigationSplitView: desde o iOS 26, as colunas aparecem e desaparecem conforme o espaço; gerenciar a visibilidade delas à mão não é mais necessário.
Materiais de sistema Liquid Glass: no iOS 27, com difusão melhorada e separação de bordas; herdados sem recompilar.
Sua própria interface tem aqui exatamente uma tarefa: não brigar com esses tijolos. As barras de topo desenhadas à mão precisam evitar os controles de fechar e minimizar no canto superior esquerdo da janela (pelo guia de layout com adaptação horizontal de cantos). Nunca suponha que a barra de abas está sempre embaixo nem a barra de ferramentas sempre em cima: a própria forma delas muda com o espaço.
7. UIKit na prática: configuração de cena e resposta à geometria
As cenas são a base da resizability: cada cena gerencia de forma independente sua própria instância de interface e estado, e fornece o contexto «onde e a que tamanho está esta interface». Desde o iOS 27, os builds com SDK recente precisam adotar o ciclo de vida UIScene: não é opcional.
Uma armação de delegado de cena para copiar tal e qual:
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 tamanho: prevenir sobreposição, não recusar redimensionamento
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
// 2) Pendurar a janela na cena; nunca UIWindow(frame: UIScreen.main.bounds)
let window = UIWindow(windowScene: windowScene)
window.rootViewController = AdaptiveRootController()
self.window = window
window.makeKeyAndVisible()
}
// 3) Callback de mudança de geometria: arrastar, Split View, desdobrar, tela externa
func windowScene(_ windowScene: UIWindowScene,
didUpdateEffectiveGeometry previous: UIWindowScene.Geometry) {
let geometry = windowScene.effectiveGeometry
let size = geometry.coordinateSpace.bounds.size
// isInteractivelyResizing significa que o usuário ainda segura a borda.
// O trabalho pesado (reconstrução de recursos, recálculo de gráficos)
// acontece uma vez, quando o gesto termina: não para cada tamanho intermediário.
if !geometry.isInteractivelyResizing,
size != previous.coordinateSpace.bounds.size {
AssetStore.shared.rebuild(for: size)
}
}
// 4) Preferência de estilo dos controles de janela (fechar / minimizar), iPadOS 26+
func preferredWindowingControlStyle(for scene: UIWindowScene)
-> UIWindowScene.WindowingControlStyle {
.unified
}
}
Três pontos merecem desdobramento:
isInteractivelyResizing é a tábua de salvação do desempenho ao arrastar. Enquanto o usuário arrasta, o sistema reporta a geometria continuamente. Se um jogo ou app reconstrói os recursos de renderização para cada tamanho intermediário, a taxa de quadros despenca no ato. A postura padrão: enquanto arrasta, só o leve (restrições, tamanhos de fonte); ao soltar, uma vez o pesado.
Nunca pegue a tela e o tamanho via UIScreen.main. No espelhamento e em tela externa, a tela principal é a resposta errada. As fontes corretas são view.window?.windowScene?.screen, a effectiveGeometry da cena, ou os view.bounds locais da view.
Evitar os controles de janela. Desde o iPadOS 26, o canto superior esquerdo da cena carrega os controles de fechar e minimizar. As barras de topo desenhadas à mão precisam se ligar a containerView.layoutGuide(for: .margins(cornerAdaptation: .horizontal)), ou seu primeiro botão fica intocável.
8. A camada das views: riscar três modos antigos
O código UIKit adaptativo é, no fundo, «três substituições»:
| Riscar | Substituir por | Por quê |
|---|---|---|
UIScreen.main.bounds |
view.bounds / effectiveGeometry / windowScene?.screen |
Em Split View e espelhamento, a tela principal não é sua janela |
Os ramos userInterfaceIdiom == .pad |
traitCollection.horizontalSizeClass |
O tipo de dispositivo não carrega semântica de layout |
Os ramos interfaceOrientation |
Classe de tamanho + limites locais | A orientação é um resultado do layout, não sua causa |
Depois da troca, a mudança de trait pilota o layout:
class AdaptiveRootController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Rearranjar na mudança de classe de tamanho; o registro cobre também
// a invalidação de cache que o rastreamento automático não vê
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()
// Quando o julgamento é mais fino que uma classe de tamanho: tamanho local disponível
fineTune(for: view.bounds.size)
}
}
Note que viewDidLayoutSubviews / layoutSubviews agem de forma contínua: a mudança de classe de tamanho dispara o «rearranjo estrutural», a mudança de limites dispara o «ajuste fino». Ler o tamanho uma única vez em onAppear / viewDidLoad e guardar produz os primeiros valores velhos assim que o redimensionamento começa.
9. SwiftUI na prática: em grande medida automático, reforçado nos pontos-chave
Os apps escritos em SwiftUI saem na frente na resizability: recompilados com o Xcode 27, o suporte a redimensionamento chega sozinho, não há API nova para adotar, e os novos materiais Liquid Glass são herdados de graça. Mas «automático» não quer dizer «sem inspeção». A caixa de ferramentas do lado SwiftUI:
@Environment(\.horizontalSizeClass)/verticalSizeClass: o equivalente do trait UIKit, responde às perguntas de direção.onGeometryChange(for:of:action:): mede o contêiner, responde às perguntas de grau. Ele lê sem disparar a ocupação gulosa de espaço doGeometryReader, e só chama a action quando o valor derivado muda de verdade: um filtro natural para os tamanhos intermediários do arrasto.ViewThatFits: o declarativo «pega o primeiro que caiba», indicado quando o conteúdo troca de disposição conforme a largura.containerRelativeFrame(): dimensiona pela proporção do contêiner em vez de pontos absolutos; especialmente útil para zonas que precisam se estender sob a interface do sistema.NavigationSplitView: desde o iOS 26, a largura e a visibilidade das colunas se adaptam sozinhas; não embrulhe por cima uma gestão manual de colunas.
.windowResizability(.contentMinSize): a entrada do SwiftUI para declarar o tamanho mínimo da cena, a contraparte desizeRestrictions?.minimumSize.
Um revezamento de duas passadas típico:
struct DashboardView: View {
@Environment(\.horizontalSizeClass) private var hSize
@State private var columnCount = 1
var body: some View {
ScrollView {
MetricGrid(columns: columnCount)
}
// Passada um: a classe de tamanho decide uma coluna ou dividido
.onChange(of: hSize) { _, new in
usesSidebar = (new == .regular)
}
// Passada dois: a largura medida decide o número de colunas,
// cobrindo 507 e 1024 que ambos são "regular"
.onGeometryChange(for: CGFloat.self) { $0.size.width } action: { _, width in
columnCount = AdaptiveWindowLayoutPolicy.tier(for: width).columns
}
}
}
10. Linhas vermelhas no Info.plist e no Launch Screen
Duas linhas vermelhas vivem na configuração do projeto. Erre uma e ela detona no momento do envio:
UIRequiresFullScreenprecisa ser tratado. Obsoleto, e quem o mantém fica excluído do redimensionamento. Apague; se ele carrega uma necessidade real de compatibilidade com o passado, useUIRequiresFullScreenIgnoredStartingWithVersionpara declarar a partir de qual versão a chave é ignorada. Os jogos entram por isso no redimensionamento discreto: depois de cada arrasto concluído, comutam para uma nova configuração de tela combinada com o tamanho, o que preserva a renderização em qualidade total.O Launch Screen é obrigatório. Desde o SDK do iOS 27, um app sem Launch Screen configurado não passa no envio para a App Store (TN3208). Num projeto SwiftUI, isso em geral significa acrescentar uma configuração mínima de tela de lançamento: não continuar correndo descalço.
11. Referência rápida de antipadrões
Antes de tocar no código, passe a base de código pela peneira desses padrões. Cada ocorrência é uma dívida a pagar:
| Antipadrão | Por que quebra | Substituir por |
|---|---|---|
UIScreen.main.bounds |
Em Split View / espelhamento, não é sua janela | view.bounds locais ou geometria da cena |
Os ramos UIDevice.current.userInterfaceIdiom |
O tipo de dispositivo não tem semântica de layout | horizontalSizeClass |
interfaceOrientation / notificações de orientação |
Reportam a postura do dispositivo, não a forma da janela | Classe de tamanho + limites locais |
Limiares caseiros tipo size.width > 600 |
Contornam a semântica de traits, falham os estados intermediários do Split View | Estratégia de escalonamento de engenharia + onGeometryChange |
Ler o tamanho uma vez em onAppear |
O redimensionamento é contínuo; o cache envelhece na hora | Callbacks de trait / geometria |
| Layout largo só para o iPad | Um iPad em Slide Over se comporta como um telefone | Lógica larga e lógica estreita ambas disparadas pelo espaço |
.frame(height: 480) fixo para mapas / heróis |
Em janelas curtas, o texto escorrega para fora da primeira tela | Altura relativa ao contêiner ou adaptativa |
12. Roteiro de migração
Quatro passos, ordenados por risco e retorno:
Fase 1 · Desarmar (primeiro, bloqueia o envio): apagar UIRequiresFullScreen, acrescentar o Launch Screen, confirmar que o ciclo de vida UIScene está em uso. Esses três pontos são portas duras, sem relação com a qualidade do design; errar um trava direto no build ou na revisão.
Fase 2 · Limpar antipadrões: com a tabela da seção 11, substituir em toda a base UIScreen.main, os ramos idiom / orientação e os limites de largura caseiros. O objetivo não é «roda»: é unificar a entrada do layout sobre a semântica do espaço.
Fase 3 · Construir as duas passadas: para as telas conduzidas pelo conteúdo, estabelecer a estratégia «a classe de tamanho decide a direção + a largura medida decide o grau», e fazer convergir cada limite nu para esse lugar único. Em tela larga, limitar a largura do texto: uma linha com mais de 85 caracteres é um bug de legibilidade.
Fase 4 · Sistematizar os testes: percorrer a matriz da seção 13 tamanho por tamanho, e congelar os resultados como pontos de não regressão.
13. Matriz de teste
Os testes de resizability não se organizam por listas de dispositivos, mas por formas de espaço. Cada forma precisa responder: a funcionalidade está completa, o conteúdo está cortado, o chrome é tocável?
| Forma de espaço | O que verificar |
|---|---|
| Largura utilizável mais estreita (perto de minimumSize) | Sobreposição de elementos, botões principais tocáveis |
| Largura de telefone padrão | Linha de base do layout padrão |
| Telefone em paisagem | Em vertical compact: barra de abas na vertical, primeira tela completa |
| Janela de telefone ampliada até regular | As colunas assumem o lugar, o estado se conserva |
| Split View pela metade / Slide Over | Dois comportamentos de espaço no mesmo iPad |
| Proporções extremas larga-achatada e alta-estreita | A extensão do fundo aguenta, o conteúdo não se rasga |
| Duo externo e interno desdobrada | Layout e estado contínuos ao virar a dobradiça |
| Espelhamento de iPhone / tela externa | As consultas de tela e tamanho estão corretas |
Do lado das ferramentas, o Device Hub e as Previews do Xcode 27 oferecem um modo de redimensionamento de janela; puxar a borda muda o tamanho de forma contínua. Espelhamento e telas externas se verificam em hardware real.
14. Perguntas frequentes
Por que meu app de iPhone de repente pode ser arrastado para uma janela maior?
Não é bug: comportamento novo desde o SDK do iOS 26. Os apps de iPhone que rodam no iPad e no espelhamento de iPhone no Mac têm janelas livremente redimensionáveis. O sinal de layout correspondente é a classe de tamanho horizontal comutando de compact para regular. O velho código if idiom == .phone produz o layout errado em tais janelas: pergunte à classe de tamanho.
As classes de tamanho bastam? Por que medir a largura também?
Não bastam, e o penhasco é real. O iPad em tela cheia e a metade em Split View são ambos (regular, regular), mas as larguras diferem por um fator de dois: um cabe uma barra lateral, o outro não. As classes de tamanho decidem a direção (uma coluna ou dividido), a largura medida decide o grau (quantas colunas, de que tamanho). As duas são um revezamento, não uma escolha.
Se eu declarar minimumSize, os usuários não podem mais arrastar para menor?
minimumSize é o limite abaixo do qual seu conteúdo começaria a se embaraçar; os usuários não conseguem arrastar além dele. É um mecanismo de prevenção de sobreposição, não um portal de funcionalidade contra o redimensionamento. O que você deve é usabilidade em qualquer tamanho entre minimumSize e maximumSize. Se um tamanho falha, a adaptação está inacabada: não é razão para aumentar o mínimo.
O que acontece se eu apagar UIRequiresFullScreen?
O app entra no redimensionamento de janelas, o esperado por padrão desde o iOS 26+. Para compatibilidade com o passado, você pode usar UIRequiresFullScreenIgnoredStartingWithVersion para declarar a versão a partir da qual ignorar; os jogos entram em redimensionamento discreto e comutam depois de cada arrasto para uma configuração de tela combinada, o que preserva melhor a qualidade de renderização.
O que um app SwiftUI realmente precisa fazer?
Recompilar, e o suporte a redimensionamento já está; não há API nova para adotar. Inspecione em vez disso: código que se apoia em suposições da era do UIScreen; julgamentos de tamanho que só usam classes de tamanho sem reforço de medição; componentes de frame fixo que se rasgam nas proporções extremas. O framework cuida do macro. O componente que se rasga costuma ser aquele que você mesmo pregou.
Fontes e leitura complementar
Fontes oficiais: a sessão WWDC25 282 «Make your UIKit app more flexible», a sessão WWDC26 278 «Modernize your UIKit app», as seções Layout e Designing for iPhone Duo das Human Interface Guidelines, a documentação de UISceneSizeRestrictions e UIWindowScene.Geometry, e as notas técnicas TN3192: migração da chave UIRequiresFullScreen obsoleta e TN3208: requisitos do Launch Screen.
Leitura complementar neste site: para ver o mesmo pensamento aterrissar de ponta a ponta num dispositivo concreto, leia Criar para o iPhone Duo, do layout ao código. Para a outra face: os dados também precisam se contrair com o espaço, veja o guia da linha de base pessoal. As demais perguntas de produto e adaptação estão nas perguntas frequentes.
Continue lendo
Experimente essas ideias no Stress HRV
Baixar na App StoreEstas notas compartilham pensamento de produto para bem-estar. Não são conselho médico.