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 de GeometryReader, 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 de sizeRestrictions?.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 :

  1. UIRequiresFullScreen doit être traité. Déprécié, et qui le garde est exclu du redimensionnement. Supprimez-le ; s'il porte une vraie exigence de compatibilité ancienne, utilisez UIRequiresFullScreenIgnoredStartingWithVersion pour 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é.

  2. 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 Store

Ces notes partagent une réflexion produit pour le bien-être. Ce n’est pas un avis médical.