La resizability iOS : quand votre app ignore sur quel appareil elle tourne
Cinq principes de design, chacun posé en code : à l'ère du redimensionnement, une app ne se demande que la place qu'elle a. Avec configuration de scène, rappels de géométrie, stratégie à deux passes, lignes rouges Info.plist et matrice de test.
La resizability, c'est la possibilité pour la fenêtre d'une app d'être attrapée par le bord et glissée librement vers n'importe quelle taille, comme une fenêtre de bureau. La pensée de design qu'Apple attache à ce changement tient en une phrase : une app ne se demande plus sur quel appareil elle tourne, dans quelle orientation, sur quel écran. Elle ne se demande que la place dont elle dispose à cet instant. Vous définissez deux comportements : comment le contenu s'organise quand la place est grande, et comment quand elle est petite. Le système applique cette logique sur tous les appareils, toutes les tailles de fenêtre et toutes les positions de pliage.
Ce n'est pas une mise à jour d'API ordinaire. C'est un changement de voie dans le paradigme de mise en page depuis la naissance d'iOS. Cet article décompose la pensée de design en cinq principes, fait atterrir chacun dans du code UIKit et SwiftUI, et se termine par une feuille de route de migration et une matrice de test que vous pouvez exécuter telles quelles.
Les signatures du texte sont vérifiées contre le SDK iOS 27.1 de Xcode 27.1. Le comportement suit la documentation Apple et les sessions WWDC, dont les sources sont listées en fin d'article. Le corps du texte est une reprise et une mise en forme technique, pas une traduction d'une page particulière.
1. D'iOS 26 à 27 : comment le redimensionnement est devenu le défaut
Avant la pensée de design, la frise. Elle explique pourquoi l'ancienne façon de faire ne suffit plus.
| Étape | Ce qui s'est passé | Ce que cela signifie pour vous |
|---|---|---|
| iPadOS 15 | Split View / Slide Over / Stage Manager | L'iPad voit apparaître des tailles hors plein écran |
| iPadOS 26 | L'iPad entre dans l'ère des fenêtres libres | L'hypothèse « iPad = regular » se met à flancher |
| SDK iOS 26 | UIRequiresFullScreen est déprécié |
Plus de sortie du redimensionnement par la touche plein écran |
| SDK iOS 26 | Les apps iPhone se redimensionnent aussi sur iPad et en miroir sur Mac | « Tourner sur iPhone » ne veut plus dire compact |
| iOS 27 | Le cycle de vie UIScene devient obligatoire pour les builds au SDK récent | Les scènes deviennent le socle |
| iOS 27 | Barres d'onglets, barres d'outils : les composants système s'adaptent à tout rapport d'aspect | Les briques système font le gros du travail |
Le fil en une phrase : la taille de fenêtre est passée d'une valeur énumérée à une valeur continue. Avant, votre app faisait face à 375, 393, 414, 768, 1024. Maintenant un doigt attrape le bord de la fenêtre et tire : la largeur peut être n'importe quel nombre entre 320 et la limite de l'écran. Une mise en page écrite pour des paliers discrets casse à coup sûr face à une valeur continue.
2. Principe un : de la pensée par appareil à la pensée par espace
La plupart des savoirs anciens en mise en page reposent sur la pensée par appareil : c'est un iPhone, il est en paysage, donc on dispose ainsi ; c'est un iPad, donc on coupe en deux. La resizability demande de remplacer entièrement cette pensée.
| Pensée par appareil (ancienne) | Pensée par espace (nouvelle) | |
|---|---|---|
| Critère de décision | Type d'appareil, orientation, taille d'écran | Espace disponible du conteneur courant |
| Nombre de mises en page | Une version par appareil | Un jeu de règles pour tous les espaces |
| Nouveau matériel | Peut demander du code et une livraison | S'applique automatiquement, zéro changement |
| Positions de pliage | Une interface de plus par posture | Une interface qui s'étire avec la largeur |
| Odeur dans le code | if idiom == .pad, isLandscape |
horizontalSizeClass, largeur du conteneur |
La formulation la plus nue de la pensée par espace vient de la WWDC : vous ne dessinez pas pour chaque plateforme ni chaque taille de fenêtre. Vous définissez une fois comment le contenu se comporte quand il y a plus de place et quand il y en a moins. Le système applique cette logique à tous les rapports d'aspect. Tourner l'écran n'est qu'un déclencheur de cette logique, de même nature que glisser une fenêtre, entrer en Split View ou déplier un écran : tout ramène au même point unique : l'espace disponible a changé.
3. Principe deux : les classes de taille sont la nouvelle lingua franca
Une fois la pensée par appareil partie, qui reprend le flambeau ? La classe de taille. C'est le jugement qualitatif que le framework porte sur l'espace : deux axes, deux mots par axe : compact signifie serré, regular signifie ample.
L'axe horizontal juge la gauche et la droite : en compact, le contenu doit s'empiler en une colonne ; c'est seulement en regular que colonnes, alignement côte à côte et barre latérale deviennent honnêtes.
L'axe vertical juge le haut et le bas : en compact, le chrome vertical (barre d'onglets, barre d'outils) ne tient plus, et le système dresse une barre d'onglets horizontale à la verticale. En regular, les barres haute et basse coexistent.
En SwiftUI, la lecture est directe :
@Environment(\.horizontalSizeClass) private var hSize // UserInterfaceSizeClass?
@Environment(\.verticalSizeClass) private var vSize
if hSize == .regular {
// De la place à gauche et à droite : colonnes / barre latérale / deux rangs
} else {
// Serré à gauche et à droite : une colonne empilée
}
En UIKit, traitCollection.horizontalSizeClass porte la même charge, et registerForTraitChanges permet de s'abonner aux changements avec précision.
Voici le plus important tableau de cet article : les classes de taille ne sont pas en correspondance biunivoque avec l'appareil et l'orientation :
| Scène | Horizontal | Vertical | Remarque |
|---|---|---|---|
| iPhone portrait | compact | regular | La forme par défaut de toute l'app |
| iPhone paysage | compact | compact | Environ 320 pt de haut seulement, la barre passe à la verticale |
| Fenêtre iPhone agrandie (iOS 26+) | regular | regular | Change à l'exécution, pas au lancement |
| iPad plein écran | regular | regular | Environ 1024 pt de large |
| iPad en Split View à moitié | regular | regular | Environ 507 pt de large, toujours regular |
| iPad en Slide Over | compact | compact | Une forme compact sur iPad |
| Écran externe du Duo | compact | compact | Environ 466 pt de large |
| Écran interne du Duo déplié | regular | compact | Change à l'exécution selon le pliage |
Lisez ce tableau trois fois et deux conclusions contre-intuitives émergent : « tourner sur un iPhone » ne veut plus dire compact (une fenêtre agrandie est regular), et « tourner sur un iPad » ne veut plus dire dire regular (Slide Over est compact). Ni le type d'appareil ni l'orientation ne répondent à « quelle mise en page dois-je utiliser maintenant ». Il faut demander à la classe de taille, à l'exécution.
Le tableau corrige aussi une vieille croyance : tourner l'appareil ne veut pas dire « l'appareil a changé ». Tourner fait basculer le couple (H, V) de (compact, regular) vers (compact, compact) et change les bornes une fois. La structure de votre code de mise en page ne bouge pas ; ce qui bouge, c'est l'entrée. À l'époque où l'orientation était un concept de mise en page, c'était toujours une variable de substitution. La substitution a disparu. Il ne reste que l'espace.
La falaise des classes de taille : pourquoi une seconde passe est nécessaire
Les classes de taille sont binaires, et assez grossières pour « mentir ». Voyez la falaise : l'iPad plein écran à 1024 pt et la moitié en Split View à 507 pt sont tous deux (regular, regular) : mais l'un accueille une barre latérale, l'autre non. Deux mots ne peuvent pas répondre aux questions de degré : combien de colonnes, quelle taille, faut-il borner la largeur.
La manière aboutie est donc un relais à deux passes : les classes de taille répondent aux questions de direction (une colonne ou découpé), la stratégie d'ingénierie répond aux questions de degré (combien de colonnes, taille du héros, largeur de lecture). La seconde passe découpe typiquement selon la largeur mesurée du conteneur : sur un écran large, elle borne le texte à une longueur de ligne confortable, ou elle déduit le nombre de colonnes de la taille minimale du contenu. Depuis iOS 17, SwiftUI peut mesurer directement la taille du conteneur avec onGeometryChange et l'injecter dans la décision : nul besoin de retomber sur GeometryReader.
4. Principe trois : la fonctionnalité ne change pas avec la taille, seulement la quantité visible
Voici un principe des Human Interface Guidelines facile à manquer mais impossible à surestimer : quand la classe de taille change, l'ensemble des fonctionnalités reste identique. Ce qui change, c'est « combien on en voit d'un coup ».
Sur un écran large, la barre d'onglets se déploie en barre latérale et révèle les destinations de second niveau. Dans une fenêtre étroite, les outils de basse priorité partent dans le menu de débordement et restent à un toucher. Ranger est un réarrangement, pas une suppression. Si une action existe dans la mise en page large et disparaît sans trace dans l'étroite, ce n'est pas de l'adaptation, c'est une fonctionnalité manquante. De même, il ne doit jamais exister, entre portrait et paysage, un écran « qui ne s'utilise complètement que dans une orientation » : ce qui marche en portrait doit marcher de bout en bout en paysage.
L'exigence implicite pour le concepteur : dans l'architecture d'information, écrire une priorité pour chaque élément. Le partage et les actions principales ont une priorité haute et résident à toute taille. L'enregistrement et les réglages secondaires ont une priorité basse : résidents au large, dans le débordement à l'étroit. Le mécanisme Visibility Priority des composants système fait exactement cela.
5. Principe quatre : les tailles min / max préviennent le chevauchement, elles ne refusent pas le redimensionnement
UIKit permet à une scène de déclarer une taille minimale et une taille maximale. Mais la sémantique doit être claire : ces deux valeurs existent pour éviter que les éléments se recouvrent aux petites tailles et ne s'étiolent aux grandes. Ce ne sont pas un obstacle que l'utilisateur doit franchir avant d'avoir le droit de tirer. À partir du moment où une fenêtre peut être tirée à toute taille, votre responsabilité est de garder le contenu utilisable, lisible et sans chevauchement à toute taille. Si une taille précise casse inévitablement, c'est que votre taille minimale était trop gourmande, ou que la mise en page n'est pas encore réellement adaptative.
Déclaration au moment de la connexion de la scène :
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
options: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
// Borne basse : en dessous, les éléments commencent à se chevaucher.
// Borne haute : au-dessus, la mise en page se relâche.
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
}
La vieille dette qui va avec : UIRequiresFullScreen est déprécié, et qui le garde reste exclu du redimensionnement : il abandonne automatiquement les nouvelles tailles d'écran. Depuis le SDK iOS 26, les apps n'ont besoin ni de changer de code ni de resoumettre pour de nouveaux écrans ; le système s'adapte automatiquement, à condition que vous ne verrouilliez pas la porte vous-même.
6. Principe cinq : laissez les composants système faire le travail
La stratégie la moins coûteuse à l'ère de la resizability est de confier le réarrangement aux composants système. Leur traitement des rapports d'aspect arbitraires est plus robuste que n'importe quelle mise en page écrite à la main :
Barres d'onglets et barres d'outils : quand la fenêtre s'élargit, les icônes restent sur la même ligne que leurs libellés et gardent la barre compacte ; quand elle se resserre, les outils de basse priorité coulent vers le menu de débordement. Dans une app d'actualité, « Partager » peut être épinglé à toute taille, « Enregistrer » ne déborder qu'à l'étroit : déclaré par Visibility Priority, sans une ligne de code de mise en page.
Barres latérales : depuis iPadOS 26, les apps iPhone peuvent aussi choisir une mise en page à barre latérale quand la place le permet, protégée par
sidebar.isAvailable.NavigationSplitView : depuis iOS 26, les colonnes apparaissent et disparaissent selon la place ; gérer leur visibilité à la main n'est plus nécessaire.
Matériaux Liquid Glass : sur iOS 27, diffusion améliorée et séparation des bords ; hérités sans recompilation.
Votre propre UI n'a ici qu'une seule tâche : ne pas se battre avec ces briques. Les barres hautes dessinées à la main doivent éviter les commandes fermer et minimiser en haut à gauche de la fenêtre (via le guide de disposition avec adaptation horizontale des coins). Ne supposez jamais que la barre d'onglets est toujours en bas ni la barre d'outils toujours en haut : leur forme même change avec l'espace.
7. UIKit en pratique : configuration de scène et réponse à la géométrie
Les scènes sont le socle de la resizability : chaque scène gère indépendamment sa propre instance d'UI et d'état, et fournit le contexte « où et à quelle taille se trouve cette UI ». Depuis iOS 27, les builds au SDK récent doivent adopter le cycle de vie UIScene : ce n'est pas optionnel.
Une charpente de délégué de scène à recopier telle quelle :
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) Déclarer les capacités de taille : prévenir le chevauchement, ne pas refuser le redimensionnement
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 320, height: 480)
// 2) Accrocher la fenêtre à la scène ; jamais UIWindow(frame: UIScreen.main.bounds)
let window = UIWindow(windowScene: windowScene)
window.rootViewController = AdaptiveRootController()
self.window = window
window.makeKeyAndVisible()
}
// 3) Rappel de changement de géométrie : glisser, Split View, déplier, écran externe
func windowScene(_ windowScene: UIWindowScene,
didUpdateEffectiveGeometry previous: UIWindowScene.Geometry) {
let geometry = windowScene.effectiveGeometry
let size = geometry.coordinateSpace.bounds.size
// isInteractivelyResizing signifie que l'utilisateur tient encore le bord.
// Le travail lourd (reconstruction des ressources, recalcul des graphiques)
// se fait une fois, quand le geste se termine : pas pour chaque taille intermédiaire.
if !geometry.isInteractivelyResizing,
size != previous.coordinateSpace.bounds.size {
AssetStore.shared.rebuild(for: size)
}
}
// 4) Préférence de style des commandes de fenêtre (fermer / minimiser), iPadOS 26+
func preferredWindowingControlStyle(for scene: UIWindowScene)
-> UIWindowScene.WindowingControlStyle {
.unified
}
}
Trois points méritent d'être dépliés :
isInteractivelyResizing est la bouée de sauvetage de la performance au glisser. Pendant que l'utilisateur tire, le système remonte la géométrie en continu. Si un jeu ou une app reconstruit ses ressources de rendu pour chaque taille intermédiaire, la fréquence d'images s'effondre sur place. La posture standard : pendant le glisser, que du léger (contraintes, tailles de police) ; après le relâchement, une fois le lourd.
Ne prenez jamais l'écran et la taille via UIScreen.main. En miroir et sur écran externe, l'écran principal est la mauvaise réponse. Les bonnes sources sont view.window?.windowScene?.screen, l'effectiveGeometry de la scène, ou les view.bounds locales de la vue.
Éviter les commandes de fenêtre. Depuis iPadOS 26, le coin supérieur gauche de la scène porte les commandes fermer et minimiser. Les barres hautes dessinées à la main doivent se lier à containerView.layoutGuide(for: .margins(cornerAdaptation: .horizontal)), sinon votre premier bouton devient intouchable.
8. La couche des vues : rayer trois anciens motifs
Le code UIKit adaptatif est, au fond, « trois remplacements » :
| Rayer | Remplacer par | Pourquoi |
|---|---|---|
UIScreen.main.bounds |
view.bounds / effectiveGeometry / windowScene?.screen |
En Split View et en miroir, l'écran principal n'est pas votre fenêtre |
Les branchements userInterfaceIdiom == .pad |
traitCollection.horizontalSizeClass |
Le type d'appareil ne porte aucune sémantique de mise en page |
Les branchements interfaceOrientation |
Classe de taille + bornes locales | L'orientation est un résultat de la mise en page, pas sa cause |
Après l'échange, le changement de trait pilote la mise en page :
class AdaptiveRootController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Réarranger au changement de classe de taille ; l'enregistrement couvre
// aussi l'invalidation de cache que le suivi automatique ne voit pas
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()
// Quand le jugement est plus fin qu'une classe de taille : taille locale disponible
fineTune(for: view.bounds.size)
}
}
Notez que viewDidLayoutSubviews / layoutSubviews agissent en continu : le changement de classe de taille déclenche le « réarrangement structurel », le changement de bornes déclenche le « réglage fin ». Lire la taille une seule fois dans onAppear / viewDidLoad et la garder produit les premières valeurs périmées dès que le redimensionnement commence.
9. SwiftUI en pratique : largement automatique, appointé aux points clés
Les apps écrites en SwiftUI partent avec une longueur d'avance sur la resizability : recompilées avec Xcode 27, le support du redimensionnement arrive automatiquement, aucune nouvelle API à adopter, et les nouveaux matériaux Liquid Glass sont hérités au passage. Mais « automatique » ne veut pas dire « sans inspection ». La boîte à outils côté SwiftUI :
@Environment(\.horizontalSizeClass)/verticalSizeClass: équivalent du trait UIKit, répond aux questions de direction.onGeometryChange(for:of:action:): mesure le conteneur, répond aux questions de degré. Il lit sans déclencher la prise de place gourmande deGeometryReader, et n'appelle l'action que quand la valeur dérivée change vraiment : un filtre naturel pour les tailles intermédiaires du glisser.ViewThatFits: le déclaratif « prends le premier qui rentre », indiqué quand le contenu change d'arrangement selon la largeur.containerRelativeFrame(): dimensionne selon le rapport du conteneur plutôt qu'en points absolus ; particulièrement utile pour les zones qui doivent s'étendre sous l'UI système.NavigationSplitView : depuis iOS 26, largeur et visibilité des colonnes s'adaptent d'elles-mêmes ; n'enroulez pas par-dessus une gestion manuelle des colonnes.
.windowResizability(.contentMinSize): l'entrée SwiftUI pour déclarer la taille minimale de scène, pendant desizeRestrictions?.minimumSize.
Un relais à deux passes typique :
struct DashboardView: View {
@Environment(\.horizontalSizeClass) private var hSize
@State private var columnCount = 1
var body: some View {
ScrollView {
MetricGrid(columns: columnCount)
}
// Passe une : la classe de taille décide une colonne ou découpé
.onChange(of: hSize) { _, new in
usesSidebar = (new == .regular)
}
// Passe deux : la largeur mesurée décide du nombre de colonnes,
// couvrant 507 et 1024 qui sont tous deux "regular"
.onGeometryChange(for: CGFloat.self) { $0.size.width } action: { _, width in
columnCount = AdaptiveWindowLayoutPolicy.tier(for: width).columns
}
}
}
10. Lignes rouges dans Info.plist et Launch Screen
Deux lignes rouges vivent dans la configuration du projet. Manquez-en une, et elle détonne au moment de la soumission :
UIRequiresFullScreendoit être traité. Déprécié, et qui le garde est exclu du redimensionnement. Supprimez-le ; s'il porte une vraie exigence de compatibilité ancienne, utilisezUIRequiresFullScreenIgnoredStartingWithVersionpour déclarer à partir de quelle version la clé est ignorée. Les jeux entrent de ce fait en redimensionnement discret : après chaque glisser abouti, ils basculent vers une nouvelle configuration d'écran assortie à la taille, ce qui préserve le rendu pleine qualité.Le Launch Screen est obligatoire. Depuis le SDK iOS 27, une app sans Launch Screen configuré ne peut pas passer la soumission App Store (TN3208). Dans un projet SwiftUI, cela signifie en général d'ajouter une configuration minimale d'écran de lancement : pas de continuer à courir nu-pieds.
11. Référence rapide des anti-patrons
Avant de toucher au code, passez la base de code au peigne fin de ces motifs. Chaque occurrence est une dette à rembourser :
| Anti-patron | Pourquoi il casse | Remplacer par |
|---|---|---|
UIScreen.main.bounds |
En Split View / miroir, ce n'est pas votre fenêtre | view.bounds locales ou géométrie de scène |
Branchements UIDevice.current.userInterfaceIdiom |
Le type d'appareil n'a pas de sémantique de mise en page | horizontalSizeClass |
interfaceOrientation / notifications d'orientation |
Rapportent la posture de l'appareil, pas la forme de la fenêtre | Classe de taille + bornes locales |
Seuils maison du type size.width > 600 |
Contournent la sémantique des traits, ratent les états intermédiaires du Split View | Stratégie de découpage d'ingénierie + onGeometryChange |
Lire la taille une fois dans onAppear |
Le redimensionnement est continu ; le cache périme aussitôt | Rappels de trait / de géométrie |
| Mise en page large seulement pour l'iPad | Un iPad en Slide Over se comporte comme un téléphone | Logique large et logique étroite déclenchées par l'espace |
.frame(height: 480) en dur pour cartes / héros |
Dans les fenêtres courtes, le texte glisse hors du premier écran | Hauteur relative au conteneur ou adaptative |
12. Feuille de route de migration
Quatre pas, ordonnés par risque et rendement :
Phase 1 · Désamorcer (d'abord, bloque la soumission) : supprimer UIRequiresFullScreen, ajouter le Launch Screen, confirmer que le cycle de vie UIScene est en usage. Ces trois points sont des portes dures, sans rapport avec la qualité de conception ; en manquer un coince directement au build ou à la revue.
Phase 2 · Nettoyer les anti-patrons : avec le tableau de la section 11, remplacer dans toute la base UIScreen.main, les branchements idiom / orientation et les seuils de largeur maison. Le but n'est pas « ça tourne » : c'est d'unifier l'entrée de la mise en page sur la sémantique de l'espace.
Phase 3 · Bâtir les deux passes : pour les écrans menés par le contenu, établir la stratégie « la classe de taille décide la direction + la largeur mesurée décide le degré », et faire converger chaque seuil nu à cet endroit unique. Sur écran large, borner la largeur du texte : une ligne de plus de 85 caractères est un bug de lisibilité.
Phase 4 · Systématiser les tests : parcourir la matrice de la section 13 taille par taille, puis figer les résultats en points de non-régression.
13. Matrice de test
Les tests de resizability ne s'organisent pas par liste d'appareils, mais par formes d'espace. Chaque forme doit répondre : la fonctionnalité est-elle complète, le contenu est-il coupé, le chrome est-il touchable ?
| Forme d'espace | Ce qu'il faut vérifier |
|---|---|
| Largeur utilisable la plus étroite (près de minimumSize) | Chevauchement des éléments, boutons principaux touchables |
| Largeur de téléphone standard | Ligne de base de la mise en page par défaut |
| Téléphone en paysage | En vertical compact : barre d'onglets dressée, premier écran complet |
| Fenêtre de téléphone agrandie jusqu'à regular | Les colonnes prennent-elles le relais, l'état est-il conservé |
| Split View à moitié / Slide Over | Deux comportements d'espace sur le même iPad |
| Rapports extrêmes large-plat et haut-étroit | L'étirement du fond tient-il, le contenu n'est pas déchiré |
| Duo écran externe et interne déplié | Mise en page et état continus au basculement du pli |
| Miroir iPhone / écran externe | Les requêtes d'écran et de taille sont-elles correctes |
Côté outils, le Device Hub et les Préviews de Xcode 27 offrent un mode de redimensionnement de fenêtre ; tirer le bord change la taille en continu. Miroir et écrans externes se vérifient sur vrai matériel.
14. Questions fréquentes
Pourquoi mon app iPhone peut-elle soudain être glissée à une plus grande fenêtre ?
Ce n'est pas un bug : nouveau comportement depuis le SDK iOS 26. Les apps iPhone qui tournent sur iPad et dans le miroir iPhone sur Mac ont des fenêtres librement redimensionnables. Le signal de mise en page correspondant est la classe de taille horizontale qui bascule de compact à regular. L'ancien code if idiom == .phone produit la mauvaise mise en page dans de telles fenêtres : demandez à la classe de taille.
Les classes de taille suffisent-elles ? Pourquoi mesurer la largeur en plus ?
Elles ne suffisent pas, et la falaise est réelle. L'iPad plein écran et la moitié en Split View sont tous deux (regular, regular), mais leurs largeurs diffèrent du simple au double : l'un accueille une barre latérale, l'autre non. Les classes de taille décident de la direction (une colonne ou découpé), la largeur mesurée décide du degré (combien de colonnes, quelle taille). Les deux sont un relais, pas un choix.
Si je déclare minimumSize, les utilisateurs ne peuvent plus glisser plus petit ?
minimumSize est la borne en dessous de laquelle votre contenu commencerait à s'embrouiller ; les utilisateurs ne peuvent pas glisser au-delà. C'est un mécanisme de prévention du chevauchement, pas un portail de fonctionnalité contre le redimensionnement. Ce que vous devez, c'est l'utilisabilité à toute taille entre minimumSize et maximumSize. Si une taille échoue, l'adaptation est inachevée : ce n'est pas une raison d'augmenter le minimum.
Que se passe-t-il si je supprime UIRequiresFullScreen ?
L'app entre dans le redimensionnement des fenêtres, l'attendu par défaut depuis iOS 26+. Pour la compatibilité ascendante, vous pouvez utiliser UIRequiresFullScreenIgnoredStartingWithVersion pour déclarer la version d'ignoration ; les jeux entrent en redimensionnement discret et basculent après chaque glisser vers une configuration d'écran assortie, ce qui préserve mieux la qualité de rendu.
Qu'est-ce qu'une app SwiftUI doit vraiment faire ?
Recompiler, et le support du redimensionnement est là ; aucune nouvelle API à adopter. Inspectez plutôt : le code qui s'appuie sur des hypothèses de l'ère UIScreen ; les jugements de taille qui n'utilisent que les classes de taille sans appoint de mesure ; les composants à frame fixe qui se déchirent aux rapports d'aspect extrêmes. Le cadre gère le macro. Le composant qui se déchire est d'ordinaire celui que vous avez vous-même cloué.
Sources et pour aller plus loin
Sources officielles : la session WWDC25 282 « Make your UIKit app more flexible », la session WWDC26 278 « Modernize your UIKit app », les sections Layout et Designing for iPhone Duo des Human Interface Guidelines, la documentation de UISceneSizeRestrictions et de UIWindowScene.Geometry, ainsi que les notes techniques TN3192 : migration depuis la clé UIRequiresFullScreen dépréciée et TN3208 : exigences du Launch Screen.
Pour aller plus loin sur ce site : pour voir la même pensée atterrir de bout en bout sur un appareil concret, lisez Concevoir pour l'iPhone Duo, de la mise en page au code. Pour l'autre face : les données aussi doivent se contracter avec l'espace, voir le guide de la ligne de base personnelle. Les autres questions de produit et d'adaptation sont dans la FAQ.
Continuer
Essayez ces idées dans Stress HRV
Télécharger sur l'App StoreCes notes partagent une réflexion produit pour le bien-être. Ce n’est pas un avis médical.