-
Rendez votre app UIKit plus flexible
Découvrez comment vos UIKit app peuvent bénéficier d'une flexibilité accrue sur iPhone, iPad, Mac et Apple Vision Pro à l'aide des contrôleurs de vue Scènes et Conteneurs. Apprenez à libérer tout le potentiel de votre application en passant d'un cycle de vie centré sur l'app à un cycle de vie basé sur des scènes, y compris un redimensionnement amélioré des fenêtres et un mode multitâche amélioré. Explorez les améliorations apportées à UISplitViewController, telles que le redimensionnement interactif des colonnes et la prise en charge de premier ordre des colonnes d'inspecteur. Et améliorez l'adaptabilité de vos vues et commandes en adoptant de nouvelles API de mise en page.
Chapitres
- 0:00 - Introduction
- 0:58 - Scènes
- 4:58 - Contrôleurs de vue de conteneur
- 10:45 - Adaptabilité
- 15:39 - Compatibilité future
- 16:07 - Étapes suivantes
Ressources
Vidéos connexes
WWDC25
WWDC24
-
Rechercher dans cette vidéo…
-
-
3:02 - Specify the scene configuration
// Specify the scene configuration @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting sceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { if sceneSession.role == .windowExternalDisplayNonInteractive { return UISceneConfiguration(name: "Timer Scene", sessionRole: sceneSession.role) } else { return UISceneConfiguration(name: "Main Scene", sessionRole: sceneSession.role) } } } -
3:30 - Configure the UI
// Configure the UI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var timerModel = TimerModel() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let windowScene = scene as! UIWindowScene let window = UIWindow(windowScene: windowScene) window.rootViewController = TimerViewController(model: timerModel) window.makeKeyAndVisible() self.window = window } } -
3:56 - Handle life cycle events
// Handle life cycle events class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var timerModel = TimerModel() // ... func sceneDidEnterBackground(_ scene: UIScene) { timerModel.pause() } } -
4:09 - Restore UI state
// Restore UI state class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var timerModel = TimerModel() // ... func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? { let userActivity = NSUserActivity(activityType: "com.example.timer.ui-state") userActivity.userInfo = ["selectedTimeFormat": timerModel.selectedTimeFormat] return userActivity } func scene(_ scene: UIScene restoreInteractionStateWith userActivity: NSUserActivity) { if let selectedTimeFormat = userActivity?["selectedTimeFormat"] as? String { timerModel.selectedTimeFormat = selectedTimeFormat } } -
4:46 - Adapt for the split view controller layout environment
// Adapt for the split view controller layout environment override func updateConfiguration(using state: UICellConfigurationState) { // ... if state.traitCollection.splitViewControllerLayoutEnvironment == .collapsed { accessories = [.disclosureIndicator()] } else { accessories = [] } } -
6:11 - Customize the minimum, maximum, and preferred column widths
// Customize the minimum, maximum, and preferred column widths let splitViewController = // ... splitViewController.minimumPrimaryColumnWidth = 200.0 splitViewController.maximumPrimaryColumnWidth = 400.0 splitViewController.preferredSupplementaryColumnWidth = 500.0 -
7:37 - Show an inspector column
// Show an inspector column let splitViewController = // ... splitViewController.setViewController(inspectorViewController, for: .inspector) splitViewController.show(.inspector) -
9:19 - Managing tab groups
// Managing tab groups let group = UITabGroup(title: "Library", ...) group.managingNavigationController = UINavigationController() // ... // MARK: - UITabBarControllerDelegate func tabBarController( _ tabBarController: UITabBarController, displayedViewControllersFor tab: UITab, proposedViewControllers: [UIViewController]) -> [UIViewController] { if tab.identifier == "Library" && !self.allowsSelectingLibraryTab { return [] } else { return proposedViewControllers } } -
10:25 - Preferred minimum size
// Specify a preferred minimum size class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let windowScene = scene as! UIWindowScene windowScene.sizeRestrictions?.minimumSize.width = 500.0 } } -
11:57 - Position content using the layout margins guide
// Position content using the layout margins guide let containerView = // ... let contentView = // ... let contentGuide = containerView.layoutMarginsGuide NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: contentGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor), contentView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor) contentView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor) ]) -
12:34 - Specify the window control style
// Specify the window control style class SceneDelegate: UIResponder, UIWindowSceneDelegate { func preferredWindowingControlStyle( for scene: UIWindowScene) -> UIWindowScene.WindowingControlStyle { return .unified } } -
13:04 - Respect the window control area
// Respect the window control area let containerView = // ... let contentView = // ... let contentGuide = containerView.layoutGuide(for: .margins(cornerAdaptation: .horizontal) NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: contentGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor), contentView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor), contentView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor) ]) -
13:57 - Request orientation lock
// Request orientation lock class RaceViewController: UIViewController { override var prefersInterfaceOrientationLocked: Bool { return isDriving } // ... var isDriving: Bool = false { didSet { if isDriving != oldValue { setNeedsUpdateOfPrefersInterfaceOrientationLocked() } } } } -
14:18 - Observe the interface orientation lock
// Observe the interface orientation lock class SceneDelegate: UIResponder, UIWindowSceneDelegate { var game = Game() func windowScene( _ windowScene: UIWindowScene, didUpdateEffectiveGeometry previousGeometry: UIWindowScene.Geometry) { let wasLocked = previousGeometry.isInterfaceOrientationLocked let isLocked = windowScene.effectiveGeometry.isInterfaceOrientationLocked if wasLocked != isLocked { game.pauseIfNeeded(isInterfaceOrientationLocked: isLocked) } } } -
14:44 - Query whether the scene is resizing
// Query whether the scene is resizing class SceneDelegate: UIResponder, UIWindowSceneDelegate { var gameAssetManager = GameAssetManager() var previousSceneSize = CGSize.zero func windowScene( _ windowScene: UIWindowScene, didUpdateEffectiveGeometry previousGeometry: UIWindowScene.Geometry) { let geometry = windowScene.effectiveGeometry let sceneSize = geometry.coordinateSpace.bounds.size if !geometry.isInteractivelyResizing && sceneSize != previousSceneSize { previousSceneSize = sceneSize gameAssetManager.updateAssets(sceneSize: sceneSize) } } }
-
-
- 0:00 - Introduction
Rendez les apps UIKit flexibles et adaptables sur différentes tailles d’écran et plateformes à l’aide de scènes, de contrôleurs de vue de conteneur et d’autres API.
- 0:58 - Scènes
Les scènes représentent des instances distinctes de l’interface utilisateur d’une app. Chaque scène gère son état de manière indépendante et se reconnecte de manière transparente. Les scènes fournissent un contexte sur l’affichage de l’app, comme la taille de l’écran et la géométrie de la fenêtre. Dans la prochaine version importante succédant à iOS 26, l’adoption du cycle de vie UIScene sera obligatoire.
- 4:58 - Contrôleurs de vue de conteneur
Les contrôleurs de vue de conteneur tels que « UISplitViewController » et « UITabBarController » gèrent la disposition d’un ou plusieurs contrôleurs de vue enfants. Ils contribuent à rendre les apps flexibles, adaptables et personnalisables. Utilisez l’API UISceneRestrictions pour indiquer la taille minimale des scènes dans l’app.
- 10:45 - Adaptabilité
Les repères de mise en forme et les marges aident à positionner le contenu d’une app de manière cohérente dans la zone de sécurité de l’appareil. iPadOS 26 introduit un nouveau contrôle de fenêtre. Les apps peuvent spécifier « preferredWindowingControlStyle » et des guides de mise en forme pour prendre en charge ces commandes. Les interfaces utilisateur adaptatives doivent réagir rapidement aux changements de dimension et d’orientation, mais certaines apps peuvent ignorer « prefersInterfaceOrientationLocked » pour verrouiller temporairement l’orientation. Pour les opérations coûteuses en calcul, cochez « isInteractivelyResizing » pour effectuer les opérations au terme d’une interaction. « UIRequiresFullscreen » est obsolète.
- 15:39 - Compatibilité future
Avec le SDK iOS 26, les apps s’adaptent automatiquement à de nouvelles tailles d’écran sans nécessiter de mises à jour manuelles ou de nouvelles soumissions.
- 16:07 - Étapes suivantes
Pour créer une app flexible, respectez le cycle de vie des scènes, utilisez des contrôleurs de vue de conteneur et utilisez des API telles que des repères de mise en forme.