-
Deixe o seu app do UIKit mais flexível
Descubra como seu app do UIKit pode ser mais flexível no iPhone, iPad, Mac e Apple Vision Pro usando cenas e controladores de visualização de contêiner. Saiba como aproveitar todo o potencial do seu app fazendo a transição de um ciclo de vida centrado no app para um ciclo de vida baseado em cenas, incluindo redimensionamento melhorado de janelas e multitarefa aprimorada. Explore as melhorias do UISplitViewController, como redimensionamento interativo de colunas e compatibilidade avançada com colunas de inspetor. Além disso, deixe as visualizações e controles mais adaptáveis adotando novas APIs de layout.
Capítulos
- 0:00 - Introdução
- 0:58 - Cenas
- 4:58 - Controladores de visualização de contêiner
- 10:45 - Adaptabilidade
- 15:39 - Compatibilidade futura
- 16:07 - Próximas etapas
Recursos
Vídeos relacionados
WWDC25
WWDC24
-
Buscar neste vídeo...
-
-
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 - Introdução
Torne os apps do UIKit flexíveis e adaptáveis em diferentes tamanhos de tela e plataformas usando cenas, controles de visualização de contêiner e outras APIs.
- 0:58 - Cenas
As cenas representam instâncias distintas da interface do usuário de um app. Cada cena gerencia seu estado de forma independente e é restaurada perfeitamente após a reconexão. As cenas fornecem contexto sobre a tela do app, como tamanho da tela e geometria da janela. A partir do próximo grande lançamento após o iOS 26, a adoção do ciclo de vida do UIScene será obrigatória.
- 4:58 - Controladores de visualização de contêiner
Controladores de visualização de contêiner, como "UISplitViewController" e "UITabBarController", gerenciam o layout de um ou mais controladores de visualização secundários. Eles ajudam a tornar os apps flexíveis, adaptáveis e personalizáveis. Use a API UISceneRestrictions para expressar o tamanho mínimo para cenas no app.
- 10:45 - Adaptabilidade
As guias de layout e as margens ajudam a posicionar o conteúdo do app de forma consistente dentro da área segura do dispositivo. iPadOS 26 introduz um novo controle de janela. Os apps podem especificar "preferredWindowingControlStyle" e guias de layout para acomodar esses controles. As interfaces do usuário adaptáveis precisam responder rapidamente a mudanças de redimensionamento e orientação, mas alguns apps podem querer substituir "prefersInterfaceOrientationLocked" para bloquear temporariamente a orientação. Para operações computacionalmente caras, marque "isInteractivelyResizing" para executar as operações após a conclusão de uma interação. O "UIRequiresFullscreen" foi descontinuado.
- 15:39 - Compatibilidade futura
Com o SDK do iOS 26, os apps se adaptam automaticamente a novos tamanhos de tela sem a necessidade de atualizações manuais ou reenvio.
- 16:07 - Próximas etapas
Para criar um app flexível, adote o ciclo de vida da cena, use controladores de visualização de contêiner e utilize as APIs como guias de layout.