Streaming is available in most browsers,
and in the Developer app.
-
What's new in UIKit
Discover the latest updates and improvements to UIKit and learn how to build better iPadOS, iOS, and Mac Catalyst apps. We'll take you through UI refinements, productivity updates, and API enhancements, and help you explore performance improvements and security & privacy features.
Resources
Related Videos
WWDC21
- Apple’s privacy pillars in focus
- Design great actions for Shortcuts, Siri, and Suggestions
- Focus on iPad keyboard navigation
- Make blazing fast lists and collection views
- Meet privacy-preserving ad attribution
- Meet TextKit 2
- Meet the Location Button
- Meet the UIKit button system
- Qualities of a great Mac Catalyst app
- SF Symbols in UIKit and AppKit
- Take your iPad apps to the next level
- What's new in Mac Catalyst
-
Download
Welcome to "What's New in UIKit" in iOS 15. My name is Michael and later I'll be joined by my colleague Jamie.
iOS 15 is packed full of amazing new technology and features. We've updated UIKit in some exciting ways to help you adopt these new capabilities.
Together, Jamie and I will cover productivity updates, UI refinements, API enhancements, performance improvements, as well as some new security and privacy features.
Productivity is at the heart of iPadOS, and this year is no exception, with updates to iPad Multitasking, keyboard navigation, keyboard shortcuts, and iPad pointer, just to name a few. Let's start with a short demo of how we've updated Multitasking to take iPad to the next level. In Mail, we are using the new center scene Multitasking feature to make it easier than ever to focus on a single message.
Just long press on a message to open the context menu and select “Open in New Window." This will open the message in its own UIWindowScene in the center of the screen. This is a great way to focus on the task at hand. The new center scene can also be moved to Split View using drag and drop, or by choosing the Split View option in the new Multitasking menu at the top of the window scene.
Alternately, you can swipe down on the Multitasking menu and dock the scene in the new window shelf.
Adding this functionality to your app is as simple as creating a new window scene activation action. This action takes a closure that returns an activation configuration, created with an NSUserActivity that can be handled by your app. Add this action to a context menu and you're all set.
With iPadOS 13.4 we introduced the Magic Keyboard and a pointer. In iPadOS 15 we've improved pointer support by adding band selection. In addition to providing new API, we've enabled band selection by default for UICollectionViews that support multi-selection. We've also added pointer accessories that allow you to communicate additional context or hint at functionality by combining secondary shapes with any pointer style. Multiple accessories can be displayed at a time and positioned around the pointer. They have the same fluid nature as the pointer, and the system seamlessly animates between different accessory shapes and positions.
In iPadOS 15, we've completely redesigned the keyboard shortcut menu. With categorized shortcuts and built-in search, finding the shortcut you're looking for has never been easier. The new Keyboard Shortcut menu also provides increased parity between iPad and Mac Catalyst versions of your app.
To take full advantage of these new features, you need to adopt UIMenuBuilder. Implement buildMenuWithBuilder on your UIApplicationDelegate. Assign commands to one of the pre-defined categories such as “View" or “File" or even create your own custom category. To use categories, you will need to audit your application for uses of UIResponder's keyCommands property. Move any commands assigned to this property to the buildMenuWithBuilder function. To learn more about Multitasking, iPad pointer, and the new Keyboard Shortcut menu, we have an amazing video all about taking your iPad apps to the next level. We've also added rich support for focus based keyboard navigation in iPadOS 15. If you're already familiar with the focus system on tvOS, then you'll be happy to know it's now available in iPadOS as well. In fact, all focus navigation in tvOS, CarPlay, iPadOS, and Mac Catalyst are now built on UIFocusSystem. With UIFocusSystem on iPad and Mac Catalyst, the arrow keys are used to move between focus items and the tab key to move between focus groups. In this example, the Mail application is using UISplitViewController with a sidebar, and when using these standard UIKit components, keyboard navigation as demonstrated will be enabled by default in iPadOS 15. Check out "Focus on keyboard navigation" to learn more about supporting keyboard navigation in your app. Another essential productivity feature of iOS is multi-touch Drag and Drop. Introduced in iOS 11, Drag and Drop has been an essential productivity enhancement. With one simple gesture, you can seamlessly move data within the application and on iPadOS even between applications. With iOS 15, UIKit has enabled inter-app drag and drop on iPhone as well, unlocking many exciting new interactions.
For example, It's now easier than ever to quickly share an idea for a new watch band with a friend. With one gesture, you can simply drag a photo from Safari right into a Messages conversation.
The Drag and Drop APIs have not changed to support this expanded capability. For a refresh of the technical details, we have four great videos from 2017 that go in-depth on how to take advantage of Drag and Drop. Next, I'll show you some of the UI refinements in iOS 15. We refined the appearance of UIToolbar and UITabBar. This updated look removes the background material when scrolled to bottom, giving more visual clarity to your content. In UITabBar, we've enhanced support for SF Symbols, giving great results when using any of your favorite symbols.
While UIKit does its best to make this new appearance seamless in your app, there are a few issues you may encounter. You should audit your code for places where you may be setting a bar's translucent property to false and check for any UIViewControllers that have non-standard edgesForExtendedLayout. Both of these conditions will cause visual issues with the new appearance.
If the new default behavior is not appropriate for your app, just create a custom appearance and assign it to the scrollEdgeAppearance property on your bar. This property was previously only available on UINavigationBar but is now also available on UIToolbar and UITabBar. Setting a custom appearance will avoid any of the visual issues causes by the previously mentioned incompatible APIs.
Additionally, it is possible UIKit won't be able to infer the proper scroll view for observation when performing the new scroll edge appearance transitions. To directly specify the scrollView, we've added a new function on UIViewController — setContentScrollView for edge. Look at all your bars. Make sure the appearance is what you expect. Be sure to check anywhere you've done something special — it might need extra attention.
We have a new appearance for headers in iOS 15. For plain lists, section headers now display seamlessly in line with the content, and only display a visible background material when becoming pinned to the top as you scroll down. In addition, there's new padding inserted above each section header to visually separate the sections with this new design.
You should use this plain style in conjunction with index bars for fast scrubbing when list content is long as demonstrated in the Contacts app.
UIKit also offers a grouped style. This is for use in UI that doesn't contain a lot of custom or visually rich content. This is a great choice for configuration UI or registration flows similar to what you'd find in the Settings app.
The prominent header style is very similar to the existing sidebar header style used for sidebar lists on iPad. Prominent headers are a great choice to use when adapting a .sidebar list to an .insetGrouped list in a compact size class.
The alarm tab in the Clock app makes great use of this new style. And finally, we have a new extra prominent grouped style for use with content that is visually rich so that headers maintain hierarchy and avoid becoming lost.
Check out the Watch app's Face Gallery to see this style in action. To access all of these great header styles, use the UIListContentConfiguration API introduced in iOS 14. In iOS 14.5 we introduced UIListSeparatorConfiguration that allows full control over separators in a list. You can specify a configuration for the entire list, or you can override the system-generated appearance on a per-row basis, giving you full control over separators. Sheets in iOS 15 gain the ability to only cover half the screen, displayed at what we call the medium height detent. With this new half height functionality, you can optionally disable dimming behind this detent to create a non-modal experience allowing interaction both within and behind the sheet. Watch "Customize and resize sheets in UIKit" to learn about all the ways we've enhanced sheets in iOS 15.
Next up UIDatePicker. And yes, In iOS 15, we are reintroducing the wheels of time. But now, you can simply tap the time to use the keyboard for input. And with Magic Keyboard on iPad, you can even edit the time right in-line. Of course, you can still tap the screen to reveal those beautiful wheels. And with that, I'll hand it off to my colleague Jamie. Thanks, Mike! I'm going to start out looking at some more enhancements to UIKit APIs in iOS 15. Our first API enhancements is in many ways also a UI refinement. We've added new APIs to UIButton, to allow you to flexibly configure your button's look and feel.
As well as the existing Plain style, we've added Gray, which has a gray background, Tinted, which has a tinted background, and Filled, which is entirely opaque.
In addition to the new styles, buttons now better support resizing in response to the system "text size" setting known as Dynamic Type, and for the first time formally support multi-line text. These changes, and the new UIButton.Configuration API that enables them, don't just make buttons more powerful, they're also more customizable and easy to update.
Together with the UIMenu additions to buttons released in iOS 14, UIButtonConfiguration allows you to make pop-up and pull-down buttons natively in UIKit for the first time.
And, of course, if you're using UIKit on Mac, and you've chosen in Xcode to "Optimize Interface For Mac", these buttons all look and behave just as you'd expect them to.
Here's an example of how easy the API is to use. Just create a button configuration. This constructor gives the Tinted style.
The configuration's properties are used to customize the button. And then instantiate the button, passing in the configuration. It's not shown here, but the only thing left is to add an action, and add the button to your view. There's a lot more to UIButtonConfiguration than I can cover here, so there is a full video covering it, and other improvements to UIButton, in detail. Check out "Meet the UIKit Button System" to learn all about the button APIs. UIContextMenuInteraction on iOS and iPadOS now supports collapsible submenus. They appear when you tap on any item with a chevron like the "Sort By" item in this menu.
There's no new API for this. The UIMenu API already supports submenus, but prior to iOS 15, they replaced the current menu entirely when you tapped on them. This is also discussed a little more in the "Meet the UIKit Button System" video.
In iOS 13, we introduced SF Symbols — hundreds of scalable symbols that look great next to our San Francisco fonts. In iOS 15, these get even better. Not only are there additional symbols, but we've added the ability to use colors in three new ways: Hierarchical, Palette, and Multicolor. Monochrome symbols are the single-color tintable images you already know and love. Hierarchical symbols apply a single runtime-specified tint color to a hierarchy of layers. Palette symbols allow multiple colors to be explicitly specified. And Multicolor symbols, previously available only in AppKit and SwiftUI, have a fixed multicolor representation.
New APIs for using all these colorful modes are available in UIKit, SwiftUI, and AppKit.
The APIs are really easy to use. This code sets up a UIImageSymbolConfiguration to use the system orange color as a basis for hierarchical tinting, and then uses that to create this image of a hierarchically tinted orange sun symbol.
If you regularly use SFSymbols, you know they come in a few style variants. For example, filled, on circles or on rectangles.
In previous releases, these are selected by specifying dotted strings. In iOS 15, there is a new UIImage API that makes working with these variants super easy, whether you want to specify the type up-front, or to generate a variant of an existing image. This is the symbol represented by the "heart" string, and two of its variants, which can now be selected in code.
There are lots of videos about all aspects of SF Symbols in the "Design and build SF Symbols" collection, and I encourage you to check them all out.
There's more on the UIKit API specifically in "SF Symbols in UIKit and AppKit." UIContentSizeCategory traits represent the system text size setting, also called the dynamic type size, in code. You can set your labels, textfields, textviews, and image views — perhaps containing SFSymbols — to automatically adjust to the setting.
In iOS 15, we've added a new way to restrict how the traits are applied to view hierarchies. This enables you to easily set a floor or ceiling for the size. This can be a great help when you're making sure your app's text and images look great at every text size setting. Here, Clock is limiting how small its large time labels get.
Please do not use this API to unduly limit text size. These settings serve an extremely important function, and it's paramount that your app's functionality is all available, and everything is legible, to people using the highest text size setting. So as another example, you might use this to limit the growth of a headline that's already very large at the default size.
We've unified the system colors across all of our platforms. What does this mean for UIKit? Well, there are some subtle changes to some of the colors, and some colors previously only available in other frameworks are now also available in UIKit wherever your app is running. So if you've been itching to use systemMint or systemBrown in your UIKit app, now is the time.
Also new is UIColor.tintColor. It's a color that's resolved at runtime, based on the app or trait hierarchy's current tint color. It's perfect for using with the new UIButton.Configuration, and the new colorful SF Symbols APIs.
Along with UIColor, there are also enhancements to the UIColorPicker ViewController, the standard interface for mixing and picking colors. In iOS 14.5, there's a new callback, colorPickerViewController(didSelect:continuously:), that allows app UI to be updated as the color is mixed and changed, as well as when the picking is complete. TextKit 2 is the new, next-generation text layout system available in iOS, iPadOS, tvOS, and macOS. It's a powerful new system that makes it easier to express what you want to do with text, and it does it in a fast, high performance way. UIKit has adopted it behind the scenes to power UITextField, where it brings better layout to text in languages with complex scripts, like Kannada with no adoption required.
If you want to know more about TextKit 2, what it can do, and how to use it in your apps, watch "Meet TextKit 2." A UISceneSession represents an instance of your application's UI, and corresponds to an app window represented in the app switcher. Interface state is represented by an NSUserActivity. Your app provides this NSUserActivity to the system when a scene enters the background, and should use it to restore the interface state when the scene is reinstantiated. In iPadOS 15, there are a few new APIs to make this easier. There's a new way to get and set the transient state of our text input views. There's a new UIScene callback that provides a more convenient place to restore state after a storyboard loads. And there's an opportunity to extend the app launch process and delay when your app's UI becomes active if you have asynchronous model code that returns state. All our engineering efforts are focused on the UIScene-based APIs. If you're still using the old UIApplication-based lifecycle from before UIScene was introduced in iPadOS 13, now is the time to switch to UIScene. All UIKit apps can use it. Supporting multiple windows is not required, although, for iPad and Mac apps, it is a great idea.
For a refresher on UIScene, and more details on the enhanced state restoration APIs, watch "Take your iPad apps to the next level." Speaking of scenes, in UIKit in iOS 15, there are new APIs that allow apps to represent the currently sharable content that's being interacted with in each scene. They're used by the new Siri "Share This" feature on iOS and Mac, and by the NSSharingServicePickerToolbarItem on Mac Catalyst. There are a lot more details in the "Design great actions for Shortcuts, Siri, and Suggestions," and "Qualities of a great Mac Catalyst app" videos.
For our last API enhancements, we'll return to our dear friends, UICollectionView and UITableView. In iOS 14, we introduced new APIs to allow you to configure the look and feel of cells much more easily and consistently than in the past.
In iOS 15, new closure-based update handlers make it easier than ever to reconfigure your cells.
No longer do you need to create a cell subclass and override updateConfiguration using state. You can now write that code inline, in the same place you create the cells. Here, we're greying out our text when the cell is disabled. Similar closure-based functions are available in the new UIButtonConfiguration APIs too.
We've improved diffable data source to make it easier to update your collection and table views. In iOS 15, when you apply a snapshot without animating differences, the UI updates based on those changes without discarding all the existing cells. And there's new API to efficiently reconfigure items, so you can update the content displayed in existing cells when the properties of items change without their identity changing.
Every device that UIKit runs on has multiple processor cores, and powerful graphics hardware. Things should happen fast. Animations and scrolling should always be smooth. In iOS 15, there are a few enhancements and new APIs that make buildings apps with these characteristics even easier. Let's talk about a few of the ones that are available in UIKit.
First, we'll return to UICollectionView and UITableView. iOS 15 introduces changes to cell prefetching. These changes automatically take effect when you build for iOS 15. They can give apps up to twice the amount of time — almost two visual frame's worth — to prepare cells while keeping scrolling perfectly smooth.
Many cells show images. In the past, you might have noticed momentary interruptions in scrolling when the main UI queue is tied up decoding large images.
In iOS 15, app code can take more control over this process. There are new easy functions to prepare images so they're completely ready when your app needs to display them. And these functions are easy to use asynchronously, so the UI queue can be free to process events while the images are being decoded.
Many apps handle large images, but display them at small sizes. To help with this, there are new UIImage APIs that resize images more efficiently — and save memory — by using the system's knowledge about the images and the display.
For more details of these collection view and image improvements, information about how you can take advantage them, and some other great performance tips, check out "Make blazing fast lists and collection views." Swift has introduced new features that make writing asynchronous code easier than ever. Most UIKit APIs must be called on the main UI queue, and we've annotated those APIs as Main Actor to ensure that this is enforced, for the first time, at compile time. In other areas, like the new UIImage preparation features, we've tweaked our APIs to ensure that UIKit is easy and safe to use with the new asynchronous Swift language features. Check out "Meet async/await in Swift" and "Meet AsyncSequence" to get going with this new way of developing asynchronous code.
Now, security and privacy. We've built some new technology into iOS 15 that allows the system to verify what interface is really being interacted with.
We've integrated this into UIKit in a few places, and here, I'm going to talk about three that might affect your app.
First, the Location Button. OS 15 introduces a new APIs allow apps to embed buttons that grant case-by-case, one-time access to the device's current location. They do this when, and only when, they are tapped on without lots of alerts or prompts.
The API is flexible, so it can match every app's look, but behind the scenes, it ensures buttons are always clear and legible, or they won't work. There's a whole video discussing how to embed this into any app, "Meet the Location Button" I'm sure you've noticed this banner, introduced in iOS 14. It's shown when an app access data that's been copied onto the pasteboard in a different app.
In iOS 15, we're eliminating the banner any time the system can confirm that the data was accessed after deliberate interaction with a standard system paste interface. For example, a tap on the paste button in the editing menu, or a Cmd-V on a hardware keyboard.
We've also added API to provide few new standard Paste menu items.
When these are used, the notification banner is also not displayed. We provide new ways to specify "Paste," "Paste and Go," "Paste and Search," and "Paste and Match Style." For each of these, there are standard UIResponder selectors — for use with UIMenuController and UICommand — and new identifiers — for use with UIAction.
Sometimes an app wants more information about what's on the pasteboard, but doesn't need full access. In iOS 14, we introduced an API that apps can use to check if there is a number, probable web URL, or probable web search term on the pasteboard. And we use these ourselves in Calculator and Safari.
In iOS 15, this API has been greatly expanded to cover all the standard Data Detectors types. None of these will show the notice, because they don't grant access to the data itself. There are also APIs to retrieve the data values without having to parse the text yourself, although if these APIs used at any time other than after the use of a standard paste interface, the system will show the paste notice.
Our last privacy enhancement was new in iOS 14.5, and built on an early version of the technology that powers the location and paste interfaces. UIEventAttribution was developed in conjunction with the WebKit team. WebKit's Private Click Measurement feature provides Web-to-Web Click Measurement. UIEventAttribution brings PCM to UIKit, and provides App-to-Web Click Measurement. This means privacy-preserving measurement of ad clicks and taps. It's easy to use — just cover your ads with UIEventAttributionViews, and pass a UIEventAttribution object along with any URLs you open in response to ad taps.
To learn more about this, see the "Meet privacy-preserving ad attribution" video. There's also a great WebKit.org blog post entitled "Introducing Private Click Measurement." Well, that was quite a whirlwind, and we didn't even cover everything that's new. What's next? Please go and compile your app using the iOS 15 SDK. Test out new features like Drag and Drop on iPhone and our enhanced system colors. Adopt the new iOS 15 look with new buttons, bars, lists and symbols. Adopt our new iPad features for better multitasking, keyboard, and trackpad support. And use the new UIKit APIs to respect user privacy, and make even better, even faster apps, even more easily. Thank you.
-
-
1:41 - Building an "Open in New Window" action
// Building an "Open in New Window" action let newSceneAction = UIWindowScene.ActivationAction({ _ in // Create the user activity that represents the new scene content let userActivity = NSUserActivity(activityType: "com.myapp.detailscene") // Return the activation configuration return UIWindowScene.ActivationConfiguration(userActivity: userActivity) })
-
3:06 - UIMenuBuilder
class AppDelegate: UIResponder, UIApplicationDelegate { override func buildMenu(with builder: UIMenuBuilder) { // Use the builder to modify the main menu... } }
-
6:26 - UIBarAppearance
let appearance = UITabBarAppearance() appearance.backgroundEffect = nil appearance.backgroundColor = .blue tabBar.scrollEdgeAppearance = appearance let scrollView = ... // Content scroll view in your app viewController.setContentScrollView(scrollView, for: .bottom)
-
11:31 - Creating a button with UIButton.Configuration
// Creating a button with UIButton.Configuration var config = UIButton.Configuration.tinted() config.title = "Add to Cart" config.image = UIImage(systemName: "cart.badge.plus") config.imagePlacement = .trailing config.buttonSize = .large config.cornerStyle = .capsule self.addToCartButton = UIButton(configuration: config)
-
13:30 - Using a hierarchical color symbol
// Using a hierarchical color symbol let configuration = UIImage.SymbolConfiguration( hierarchicalColor: UIColor.systemOrange ) let image = UIImage( systemName: "sun.max.circle.fill", withConfiguration: configuration )
-
19:30 - New UICollectionViewCell.configurationUpdateHandler closures
// New UICollectionViewCell.configurationUpdateHandler closures let cell: UICollectionViewCell = ... cell.configurationUpdateHandler = { cell, state in var content = UIListContentConfiguration.cell().updated(for: state) content.text = "Hello world!" if state.isDisabled { content.textProperties.color = .systemGray } cell.contentConfiguration = content }
-
21:01 - Image display preparation
// Image display preparation if let image = UIImage(contentsOfFile: pathToImage) { // Prepare the image for display asynchronously. Task { let preparedImage = await image.byPreparingForDisplay() imageView.image = preparedImage } }
-
21:29 - Image thumbnailing
// Image thumbnailing if let bigImage = UIImage(contentsOfFile: pathToBigImage) { // Prepare the thumbnail asynchronously. Task { let smallImage = await bigImage.byPreparingThumbnail(ofSize: smallSize) imageView.image = smallImage } }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.