Streaming is available in most browsers,
and in the Developer app.
-
What’s new in UIKit
Modernize your app with the latest APIs in UIKit, including enhanced menu bar support, automatic observation tracking, a new UI update method, and improvements to animations. We'll also cover how you can include SwiftUI scenes in your UIKit app and explore SF Symbols, HDR color pickers, and more.
Chapters
- 0:00 - Introduction
- 0:59 - New design system
- 2:29 - Containers and adaptivity
- 3:21 - The menu bar
- 9:58 - Architectural improvements
- 10:21 - Automatic observation tracking
- 12:33 - New UI update method
- 15:45 - Improvements to animations
- 17:45 - Scene updates
- 18:55 - HDR Color support
- 20:38 - Swift notifications
- 21:20 - Migrate to a scene-based life cycle
- 22:40 - OpenURL support for file URLs
- 23:17 - SF Symbols 7
- 25:13 - Next steps
Resources
Related Videos
WWDC25
- Build a UIKit app with the new design
- Elevate the design of your iPad app
- Get to know the new design system
- Make your UIKit app more flexible
- What’s new in SF Symbols 7
WWDC24
WWDC23
WWDC21
-
Search this video…
Greetings, and welcome to “What’s new in UIKit”. I’m Dima, an engineering manager on the UIKit team. From iOS and iPadOS to tvOS, visionOS and Mac Catalyst, UIKit continues to be the foundation of your apps now with even more enhancements.
I’ll start off by giving you an overview of UIKit’s support for the new design system. Then, I’ll cover improvements for your app’s content to adapt smoothly across various devices and screen shapes. Following that, I’ll introduce new UIKit APIs for the menu bar, the familiar macOS element that’s come to iPadOS! I’ll dive into the core architectural advancements in UIKit, revisiting key fundamentals along the way. Finally, I’ll wrap up with the broader general framework enhancements we’ve made.
The new design system introduces a vibrant look for system materials and controls.
At its heart is the new material: Liquid Glass. It’s translucent, dynamic and alive with effects like specular highlights and refraction. From bars and search fields to alerts, popovers and split views, UIKit standard components have been refreshed with the new material.
Navigation transitions are now fluid and interruptible, giving your app a more responsive feel.
Users can start interacting with content without waiting for the animation to finish.
And, to elevate your own UI to the new design, we introduced new tools like the background extension view, which allows your content to surface under the sidebar’s large glass platter, preserving visual continuity.
There is also a glass material for your own custom components and the new scroll edge effect for your content to gracefully fade as it scrolls under the glass platters, enhancing legibility of bar buttons and other controls.
For a comprehensive hands-on guide to updating the look of your UIKit apps, watch the video “Build a UIKit app with the new design”. And to dive into the new design itself, checkout “Get to know the new design system”.
Next, an overview of improvements for your apps content to adapt smoothly across various devices and screen shapes.
In iOS 26, UISplitViewController gains first class support for inspectors. An inspector provides additional details of the selected content. For example, Preview uses an inspector to display metadata alongside the photo in the secondary column.
You can now also resize columns by dragging the split view controller’s separators. When using the pointer, its shape will adapt to indicate the directions in which a column can be resized. For more information on the improvements to container view controllers, as well as a refresher on general layout concepts such as layout margins and safe areas, check out the video “Make your UIKit app more flexible”. Next on the menu: iOS 26 brings the menu bar from macOS to iPad.
Now a swipe from the top reveals your app’s full menu even without a hardware keyboard! It’s a great way to provide quick access to the functionality in your app.
The menu bar supports all menu features—images, submenus, inline sections, checkmarks, and more.
It should show all commands from your app, even those without keyboard shortcuts. And it keeps unavailable commands visible, but disabled, so users can still discover everything your app is capable of.
Apps still use UIMenuBuilder to customize their main menus, and in iOS 26, UIKit is introducing several new APIs to build even better menu bars. I’ll start with the main menu system configuration.
This API allows apps to customize which system commands are initially provided in the main menu. When you use the configuration API, your app is opted into additional pre-made, localized menu elements, like the new command to toggle inspectors. And it lets you declare upfront which items to include or omit. You can also deeply configure and style individual groups of elements; for instance, optimizing the Find commands for the needs of your app. Finally, supply a UIMenuBuilder block ahead of time to add custom items, letting both your app and its share extensions use the same code to define supported keyboard shortcuts.
This is an example of using a main menu system configuration. First, I create a configuration object. Then, I specify which commands my app wants in the main menu by default. For example, I’ll declare support for the system printing commands.
I’ll opt out of certain default commands, such as the new command to toggle the inspector panel. The configuration allows me to specify common styles for the default commands, like converting the system Find commands into a single Search item. This is great for photo or music apps, where the focus is on searching content rather than searching text.
Finally, I can set the configuration on the main menu system to have it build with the initial set of preferred elements. I can also optionally provide a build handler, which will be called instead of buildMenuWithBuilder. The handler provides access to a UIMenuBuilder, which has been upgraded in iOS 26 with more powerful convenience methods, faster performance, and improved diagnostics.
Note that setting a configuration will trigger a rebuild of the menu bar.
Ideally, your app should set the configuration only once and as early as possible, such as in application didFinishLaunchingWithOptions. iOS and macOS 26 introduce additional standard actions and menus in the menu bar. Perform close is mapped to Cmd-W, and closes your window scene by default, but you can also have it close other things in your app, like tabs in a web browser. The menu command “New from clipboard” allows creation of documents from the contents of the pasteboard, without triggering a paste alert. The newItem menu introduced in iOS 26 is a great place to put it. The standard actions for text alignment, sidebar toggling, and inspector toggling are also now exposed for your apps to customize. By default, keyboard shortcuts repeat when the keys are held down but you can customize that behavior by setting the repeatBehavior property on UIKeyCommand.
This property can also be set per-responder using validateCommand. This is especially important for destructive actions like hitting a delete key to delete an email so you don’t accidentally trigger them repeatedly. In some cases, parts of the menu bar need to display dynamic content based on the focused item or a window scene.
For example, browsing apps like Safari may show history for the current browsing profile in the History menu.
To support this, use the new focus-based deferred menu element, which populates its elements from the responder chain. When constructing your main menu, create a UIDeferredMenuElement using focus, and give it an identifier to differentiate it.
Then, insert it into the main menu.
When the deferred element needs to be fulfilled, UIKit walks the responder chain until it finds a responder that can contribute items. In this example, the browser view controller overrides providerForDeferredMenuElement to supply history items for the current profile.
It checks the identifier of the deferred element for the browserHistory element and returns a Provider to load history menu items. Focus-based deferred elements are a great way to keep the menu bar up to date with keyless commands, without needing to perform costly rebuilds on the main menu system. Beyond your app’s custom items, the system supplies several menu entries automatically. Your app gets a keyboard shortcut to open its settings in the Settings app, and for document-based apps, the Open Recent menu will be populated with recent documents.
The system also supplements the Window menu with tiling commands, including a list of all open scenes for your app. Populate the title of each scene to help users differentiate them.
Finally, a few things to keep in mind as you build out your menu bar. For UIKit apps, menu bars defined in storyboards are no longer supported. Apps will not launch with menus in storyboards, so implementing them programmatically is required.
You should also ensure that your app’s functionality remains accessible without the menu bar, since the menu bar will not always be present.
To learn more about how to build a great menu bar for your app, watch “Elevate the design of your iPad app”. And for an overview of the UIKit main menu, check out “Take your iPad apps to the next level”. We are continuing to evolve UIKit with new features for modern patterns, best practices and deeper SwiftUI interoperability. iOS 26 is no exception, and I have exciting new architectural improvements to share with you. The first major enhancement is built-in support for Swift Observable objects in UIKit.
UIKit now integrates Swift Observation at its core: in update methods like layoutSubviews, it automatically tracks any Observable you reference, wires up dependencies, and invalidates the right views —no manual setNeedsLayout required.
You can back-deploy this on iOS 18 by adding the UIObservationTrackingEnabled key to your Info.plist. On iOS 26, it’s enabled by default. I’ll go over a couple of examples of automatic observation tracking in action.
Here, I have a message list view controller containing a UILabel that indicates unread messages.
It’s backed by an Observable model object with two properties, a boolean that controls whether the status is shown, and the status string.
In viewWillLayoutSubviews, I use the observable model to update the label's alpha to show or hide it, and set its text. On first layout, UIKit populates the label, and—thanks to automatic observation tracking— records dependencies on showStatus and statusText. Any change to those properties invalidates the view and reruns viewWillLayoutSubviews, keeping the label in sync without extra code. Here is another example of using Observable objects with UIKit, which highlights the benefits of automatic observation tracking when configuring cells in a UICollectionView.
I back each list cell with an observable ListItemModel containing an icon, title and subtitle.
Inside of the cell provider callback, I dequeue a cell, grab its model and assign a configurationUpdateHandler.
Because this handler supports observation tracking, UIKit automatically establishes dependencies on any Observable objects I use inside it.
In the handler I populate and apply a list content configuration using the observable list item model. That’s it! Now any change to the model’s properties while the cell is visible causes UIKit to rerun the handler and update the cell for me. With the addition of automatic trait and observation tracking, UIKit now includes a general-purpose update method to support those features.
We introduce a new method updateProperties to both UIView and UIViewController.
It runs just before layoutSubviews, but is independent, letting you invalidate properties without forcing the layout, and vice versa, so you avoid extra passes and gain finer-grained updates.
updateProperties complements, not replaces, layoutSubviews. Use it to populate content, apply styling or configure behaviors.
It automatically tracks any Observable you read and you can manually trigger it by calling setNeedsUpdateProperties. I’ll go over a concrete example of using this new method.
Here, I have an Observable BadgeModel object that stores the count displayed in a badge view. The view controller for the bar-button item is backed by a BadgeModel.
Within updateProperties I use the new badging API on the bar button item and pull the count straight from the model. Now, whenever the Observable model object changes, it results in updateProperties running and updating the badge.
By using updateProperties to configure the view instead of layoutSubviews, I avoid re-running the code on unrelated events, like resizing, cutting unnecessary work and improving performance.
To better understand how updateProperties fits in with other update methods, I’ll go over how UIKit’s update pass works.
Here is an illustration of how UIKit updates views before displaying them on screen.
The layout pass comes first. UIKit traverses the view hierarchy top down, updates each view’s traits, then calls layoutSubviews. If that pass causes other views to require layout, the layout pass repeats until everything is laid out.
Once the layout settles, UIKit performs the display pass, calling draw method on each view and repeating until all views no longer need display.
Once both passes finish, the next frame can be rendered and displayed on the screen.
And here is how the new updateProperties callback fits in. During the top-down layout pass, UIKit runs updateProperties right after updating traits and just before layoutSubviews. You can think of layoutSubviews as being split into two stages: property updates first, then the usual layout logic. Because the trait collection is updated before updateProperties runs, you can safely read it there. And since it always precedes layoutSubviews, you can invalidate layout inside it and the layout pass will run immediately afterward.
To complement the new observation tracking feature and new updateProperties method, we’ve made an improvement to how animations work in UIKit.
Before starting, I’ll go over how a manual update works in iOS 18 and earlier. In a UIView animation closure, first, the new values are set on Observable objects, then layoutIfNeeded is called on views that depend on those objects. Both steps are necessary, because the first step causes an invalidation, and the second step performs the update and creates animations. Manually maintaining property and view dependencies is prone to error, and can result in either too many or too few updates or animations.
iOS 26 has a new animation option for UIViews called flushUpdates. When enabled, UIKit applies pending updates just before the animation begins, and again when it ends, so you no longer need to call layoutIfNeeded. For flushUpdates to work, only make invalidating state changes inside the animation closure. I'll go through an example of how to use flushUpdates. First, pass flushUpdates as an option to UIView animate, then make changes to the Observable object inside the closure. Any views using that Observable object in an update method will automatically perform the necessary update. flushUpdates isn’t limited to animations driven by Observable.
Here's an example of using it to animate auto layout constraint changes automatically.
In the flushUpdates closure, I set a new constant to one of the existing constraints, and also activate and deactivate other constraints. Dependent views animate to their new positions and sizes automatically.
Now I’ll cover how we made using SwiftUI and UIKit in the same app more seamless.
SwiftUI scenes are now supported in UIKit applications using a new delegate protocol. This supports incremental adoption of SwiftUI, and also allows UIKit apps to leverage immersive spaces and volumes on visionOS.
Imagine a meditation app that presents a zen garden scene: in a standard 2D window on iPhone and iPad, and as an immersive space on visionOS.
I present that immersive space by implementing the new UIHostingSceneDelegate protocol with a root SwiftUI scene.
Using a hosting scene delegate is just like any other scene delegate. Simply set the delegate class type on the UISceneConfiguration when a new scene is connecting.
You can programmatically request a particular SwiftUI scene from the hosting delegate by passing its identifier.
In this example I request the immersive zen garden space.
Lastly, I’ll guide you through some general enhancements in UIKit, starting with improvements to HDR rendering.
With iOS 26 HDR isn’t just for images anymore—colors get the same treatment, so you can accentuate your user interface or enable new experiences.
UIColor now lets you specify a base SDR color plus an exposure value, automatically adjusting its brightness to the display’s capabilities. Here, I create a red HDR color with its exposure set to two and a half times the SDR’s peak white.
Now you can also enable HDR color selection in UIColorPickerViewController and UIColorWell. To do that, set a maximum exposure to a value guided by your app's rendering capabilities. Here I set the maximum linear exposure of the color picker to be twice the SDR’s peak white.
In iOS 18, UIImageView intelligently falls back HDR to SDR, ensuring that key content in the UI stands out.
In iOS 26 this behavior is expanded to video, and your own custom content can participate as well.
Use the new UITraitHDRHeadroomUsage trait to monitor when your HDR content should fall back to SDR. To learn more about HDR, check out the videos “Use HDR for dynamic image experiences in your app” and “Support HDR images in your app”.
Building on NSNotification.Name API, UIKit in iOS 26 now represents each notification as a dedicated NotificationCenter.Message type.
This gives you a strongly typed value for registering observers and for retrieving event details.
Here is an example of adjusting the layout when the keyboard appears: I register for the keyboardWillShow notification type, then, in the handler, I pull the animation duration and the keyboard frame straight from the message. Finally, I animate my constraints using those values—no need for userInfo lookups or manual casting! With each release, the continuous evolution of UIKit brings you modern, robust APIs for today’s best practices. And as you adopt those, we are deprecating the legacy methods.
UIScene adoption makes your apps portable and highly flexible so we’re deprecating many UIApplication focused APIs.
Legacy UIApplicationDelegate callbacks and UIApplicationLaunchOptionKeys no longer apply, and only the init windowScene initializer for UIWindow remains. Every other initializer is deprecated.
In the release following iOS 26, any UIKit app built with the latest SDK will be required to use the UIScene life cycle, otherwise it will not launch.
Adopt the UIScene life cycle everywhere, not just in multi-window apps! For details on how to do that, read the tech note: “Migrating to the UIKit scene-based life cycle”. For more information on how to maximize the flexibility of your app, including new APIs that will help you migrate away from UIRequiresFullScreen, check out the video “Make your UIKit app more flexible”.
Apps dealing with a variety of document types frequently need to launch external viewers.
In iOS 26 the existing openURL method now accepts file URLs so you can now hand-off documents that are not natively supported by your app. If a default app exists for that file type, the system launches it and passes along your URL. If not, openURL returns false, giving you an option to handle the fallback yourself, for example, by using a quick look preview controller.
SF Symbols got improved in iOS 26. SF Symbols 7 adds the ability to draw symbols, starting with two new effects.
Draw Off, like the Disappear effect, uses the draw animation to hide a symbol. Draw On, like Appear, shows a hidden symbol by drawing it.
Symbols can now support variable draw, a new mode for variable value. This draws arbitrary values along a path, such as for this progress indicator. You can also use it with the Automatic symbol content transition to animate across variable values.
Magic Replace transitions can also perform special draw animations between certain symbols. For example, this transition between the circle symbol and the filled checkmark symbol now fills the circle and draws the checkmark. The new draw animations are incredibly useful for buttons, so UIKit has new API to easily adopt symbol content transitions in UIButton.
Use the new symbolContentTransition property on UIButton.Configuration to specify a symbol content transition, such as replace. When the button’s symbol changes, say when its selection state toggles, UIKit performs the transition. SF Symbols 7 introduces other capabilities, too, like the new color rendering mode option. Apps can specify Gradient to color their symbols using automatically-generated gradients rather than flat colors.
To learn how to fully customize drawing and gradients, watch “What’s new in SF Symbols 7”.
And for a refresher on how to use symbol effects for animation, check out “Animate symbols in your app”.
What’s next? Compile your app using the iOS 26 SDK. Review how your app responds to the new design and refine your UIs and styling to match the new aesthetics.
Use standard containers like UISplitViewController and UITabBarController to get support for flexible layouts. Implement your app’s menus with the new menu APIs. And adopt updateProperties method and observation tracking to streamline your code and improve performance.
Thank you! I’m excited to see how you use these improvements to make your apps even more powerful and delightful to use!
-
-
4:56 - Main menu system configuration
// Main menu system configuration var config = UIMainMenuSystem.Configuration() // Declare support for default commands, like printing config.printingPreference = .included // Opt out of default commands, like inspector config.inspectorPreference = .removed // Configure the Find commands to be a single "Search" element config.findingConfiguration.style = .search
-
5:39 - Main menu system build configuration
// Main menu system configuration // Have the main menu system build using this configuration, and make custom additions. // Call this early, e.g. in application(_:didFinishLaunchingWithOptions:), and call it once UIMainMenuSystem.shared.setBuildConfiguration(config) { builder in builder.insertElements([...], afterCommand: #selector(copy(_:))) let deleteKeyCommand = UIKeyCommand(...) builder.replace(command: #selector(delete(_:)), withElements: [deleteKeyCommand]) }
-
7:01 - Keyboard shortcut repeatability
// Keyboard shortcut repeatability let keyCommand = UIKeyCommand(...) keyCommand.repeatBehavior = .nonRepeatable
-
7:43 - Focus-based deferred menu elements (App Delegate)
// Focus-based deferred menu elements extension UIDeferredMenuElement.Identifier { static let browserHistory: Self = .init(rawValue: "com.example.deferred-element.history") } // Create a focus-based deferred element that will display browser history let historyDeferredElement = UIDeferredMenuElement.usingFocus( identifier: .browserHistory, shouldCacheItems: false ) // Insert it into the app’s custom History menu when building the main menu builder.insertElements([historyDeferredElement], atEndOfMenu: .history)
-
8:06 - Focus-based deferred menu elements (View Controller)
// Focus-based deferred menu elements class BrowserViewController: UIViewController { // ... override func provider( for deferredElement: UIDeferredMenuElement ) -> UIDeferredMenuElement.Provider? { if deferredElement.identifier == .browserHistory { return UIDeferredMenuElement.Provider { completion in let browserHistoryMenuElements = profile.browserHistoryElements() completion(browserHistoryMenuElements) } } return nil } }
-
10:54 - Using an Observable object and automatic observation tracking
// Using an Observable object and automatic observation tracking @Observable class UnreadMessagesModel { var showStatus: Bool var statusText: String } class MessageListViewController: UIViewController { var unreadMessagesModel: UnreadMessagesModel var statusLabel: UILabel override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() statusLabel.alpha = unreadMessagesModel.showStatus ? 1.0 : 0.0 statusLabel.text = unreadMessagesModel.statusText } }
-
11:48 - Configuring a UICollectionView cell with automatic observation tracking
// Configuring a UICollectionView cell with automatic observation tracking @Observable class ListItemModel { var icon: UIImage var title: String var subtitle: String } func collectionView( _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath ) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) let listItemModel = listItemModel(for: indexPath) cell.configurationUpdateHandler = { cell, state in var content = UIListContentConfiguration.subtitleCell() content.image = listItemModel.icon content.text = listItemModel.title content.secondaryText = listItemModel.subtitle cell.contentConfiguration = content } return cell }
-
13:27 - Using automatic observation tracking and updateProperties()
// Using automatic observation tracking and updateProperties() @Observable class BadgeModel { var badgeCount: Int? } class MyViewController: UIViewController { var model: BadgeModel let folderButton: UIBarButtonItem override func updateProperties() { super.updateProperties() if let badgeCount = model.badgeCount { folderButton.badge = .count(badgeCount) } else { folderButton.badge = nil } } }
-
16:57 - Using the flushUpdates animation option to automatically animate updates
// Using the flushUpdates animation option to automatically animate updates // Automatically animate changes with Observable objects UIView.animate(options: .flushUpdates) { model.badgeColor = .red }
-
17:23 - Automatically animate changes to Auto Layout constraints with flushUpdates
// Automatically animate changes to Auto Layout constraints UIView.animate(options: .flushUpdates) { // Change the constant of a NSLayoutConstraint topSpacingConstraint.constant = 20 // Change which constraints are active leadingEdgeConstraint.isActive = false trailingEdgeConstraint.isActive = true }
-
18:07 - Setting up a UIHostingSceneDelegate
// Setting up a UIHostingSceneDelegate import UIKit import SwiftUI class ZenGardenSceneDelegate: UIResponder, UIHostingSceneDelegate { static var rootScene: some Scene { WindowGroup(id: "zengarden") { ZenGardenView() } #if os(visionOS) ImmersiveSpace(id: "zengardenspace") { ZenGardenSpace() } .immersionStyle(selection: .constant(.full), in: .mixed, .progressive, .full) #endif } }
-
18:28 - Using a UIHostingSceneDelegate
// Using a UIHostingSceneDelegate func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { let configuration = UISceneConfiguration(name: "Zen Garden Scene", sessionRole: connectingSceneSession.role) configuration.delegateClass = ZenGardenSceneDelegate.self return configuration }
-
18:41 - Requesting a scene
// Requesting a scene func openZenGardenSpace() { let request = UISceneSessionActivationRequest( hostingDelegateClass: ZenGardenSceneDelegate.self, id: “zengardenspace")! UIApplication.shared.activateSceneSession(for: request) }
-
19:18 - HDR color support
// Create an HDR red relative to a 2.5x peak white let hdrRed = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0, linearExposure: 2.5)
-
19:50 - HDR color picking
// Support picking HDR colors relative to a // maximum peak white of 2x colorPickerController.maximumLinearExposure = 2.0
-
20:06 - Mixing SDR and HDR content
// Mixing SDR and HDR content registerForTraitChanges([UITraitHDRHeadroomUsageLimit.self]) { traitEnvironment, previousTraitCollection in let currentHeadroomLimit = traitEnvironment.traitCollection.hdrHeadroomUsageLimit // Update HDR usage based on currentHeadroomLimit’s value }
-
20:54 - Adopting Swift notifications
// Adopting Swift notifications override func viewDidLoad() { super.viewDidLoad() let keyboardObserver = NotificationCenter.default.addObserver( of: UIScreen.self for: .keyboardWillShow ) { message in UIView.animate( withDuration: message.animationDuration, delay: 0, options: .flushUpdates ) { // Use message.endFrame to animate the layout of views with the keyboard let keyboardOverlap = view.bounds.maxY - message.endFrame.minY bottomConstraint.constant = keyboardOverlap } } }
-
24:26 - Using a symbol content transition to automatically animate symbol updates
// Using a symbol content transition to automatically animate symbol updates var configuration = UIButton.Configuration.plain() configuration.symbolContentTransition = UISymbolContentTransition(.replace)
-
-
- 0:00 - Introduction
Learn about UIKit's enhancements across iOS, iPadOS, tvOS, visionOS, and Mac Catalyst. This video covers the new design system, containers and adaptivity, APIs for the menu bar on iPadOS and Mac Catalyst, core architectural advancements, and general framework improvements.
- 0:59 - New design system
The new design system features Liquid Glass: a translucent, dynamic material that refreshes standard UIKit components and enhances navigation transitions. UIKit also has new API for bringing Liquid Glass to your custom UI.
- 2:29 - Containers and adaptivity
iOS 26 enhances 'UISplitViewController' with inspectors for detailed content display and dynamic column resizing.
- 3:21 - The menu bar
iOS 26 improves the menu bar on iPad, which is now accessible via a swipe from the top of the screen, to provide quick access to app functionality without a hardware keyboard. The menu bar should always display all app commands, even those that are disabled or without keyboard shortcuts. Customize the menu bar using the new API for main menu configuration, and implement dynamic menus based on the focused view. Standard actions like 'Close', and 'New from Clipboard' are introduced. Actions for text alignment, sidebar toggling, and inspector toggling are now exposed for customization. Make sure that actions are available in your app without relying on the menu bar.
- 9:58 - Architectural improvements
UIKit continues to evolve with new features for modern patterns, best practices and deeper SwiftUI interoperability.
- 10:21 - Automatic observation tracking
UIKit now automatically tracks Observable objects referenced in update methods such as 'layoutSubviews', eliminating the need for manual calls to 'setNeedsLayout'. This feature is enabled by default in iOS 26 and you can back-deploy it to iOS 18 with the 'UIObservationTrackingEnabled' Info.plist key. Changes to Observable model properties that update UI elements automatically trigger view invalidation and reruns of the relevant update methods, keeping the UI in sync without additional code.
- 12:33 - New UI update method
UIKit introduces a new method, 'updateProperties', available in 'UIView' and 'UIViewController'. This method runs independently before 'layoutSubviews' and allows you to populate content, apply styling, and configure behaviors more efficiently. 'updateProperties' automatically tracks Observables and can otherwise be manually triggered by calling 'setNeedsUpdateProperties'. By using this method, you can avoid unnecessary layout passes, improving your app's performance.
- 15:45 - Improvements to animations
In iOS 26, UIKit introduces 'flushUpdates', an animation option that automatically applies pending updates before and after animations, eliminating the need for manual 'layoutIfNeeded' calls. This simplifies code, reduces errors, and works with Observable objects and auto layout constraint changes.
- 17:45 - Scene updates
You can now integrate SwiftUI scenes into UIKit apps using the new 'UIHostingSceneDelegate' protocol. Create apps that adapt to different devices — like a meditation app with a 2D zen garden on iPhone and iPad and an immersive visionOS experience — by programmatically requesting a specific SwiftUI scene.
- 18:55 - HDR Color support
In iOS 26, UIKit also enhances HDR rendering beyond images to include colors. Create HDR colors using 'UIColor' and enable HDR color selection in color pickers. Use the new 'UITraitHDRHeadroomUsage' trait to monitor when your HDR content should fall back to SDR.
- 20:38 - Swift notifications
UIKit represents each notification as a dedicated 'NotificationCenter.Message' type in iOS 26, providing strongly typed notifications for easier event handling, as seen in an example of adjusting layout when the keyboard appears.
- 21:20 - Migrate to a scene-based life cycle
'UIScene' replaces 'UIApplication' as the standard for app development, making apps more portable and flexible. You must adopt the 'UIScene' life cycle because legacy methods are deprecated and, starting with the release following iOS 26, apps that have not adopted the scene life cycle will not launch.
- 22:40 - OpenURL support for file URLs
The 'openURL' method now allows apps to hand off non-native documents to default viewers or use quick look preview controllers if no default exists.
- 23:17 - SF Symbols 7
SF Symbols 7 introduces new drawing capabilities including 'Draw Off' and 'Draw On' effects, variable draw mode for drawing arbitrary values along a path, and special draw animations with Magic Replace transitions. UIKit now has API for easy adoption of these transitions in 'UIButton', and symbols can be colored with automatically-generated gradients.
- 25:13 - Next steps
To update your app for iOS 26, compile with the new SDK, refine UIs to match the new design, utilize standard containers and new menu APIs, and adopt the 'updateProperties' method and observation tracking for improved performance.