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, API enhancements, and more. We'll also help you explore improvements to performance, security, and privacy.
♪ instrumental hip hop music ♪ - Welcome to "What's New in UIKit" in iOS 16. I'm Dima, and I'm an engineering manager on the UIKit team. UIKit is the powerful framework at the core of your apps. It has been updated to support new features in iOS 16.
In this video, I will cover UI improvements for productivity, Control enhancements, API refinements, and I will talk about exciting new ways to use UIKit and SwiftUI together.
We made it even easier in UIKit to develop streamlined, discoverable user interfaces with improved navigation bars that feature a new title menu, find and replace, and reimagined editing interactions for cut, copy, and paste. You will be able to enhance your document-based applications. I'll start by taking a closer look at navigation bars, updated to support desktop class toolbar capabilities.
In iOS 16, UIKit introduces two new navigation styles to better support the needs of document based apps: browser and editor.
The browser style is designed for apps that use history or folder structure for navigation, like web and document browsers.
The editor is intended for interfaces centered around editing documents.
in iOS 16, you can add a variety of bar button items to your app, a subset of which will be displayed in the center of the navigation bar.
By tapping the "customize toolbar" entry in the menu, items can be rearranged by dragging to and from the items popup.
The resulting new configuration persists across app launch.
To accommodate a size change, for example, when entering side-by-side mode with another app, the system automatically provides an overflow menu to access any items that don't fit.
We have added a title menu that works with the new navigation styles and supports a few standard functions: duplicate, move, rename, export, and print. These are displayed in the menu automatically when the corresponding delegate methods are implemented. It's also possible to add completely custom items to the title menu.
Additionally, apps built with Mac Catalyst take advantage of the improved navigation bars by seamlessly integrating with NSToolbar with no additional code required.
iOS 16 introduces new ways to manipulate text consistently across various apps. The first one is the new find and replace. Conceptually, it is different from the more high-level in-app search that operates on data model objects such as photos or calendar events. Instead, find and replace is purposefully built to work with text. It only takes setting a flag to activate the feature for built-in UIKit views such as UITextView and WKWebView.
Additionally, it seamlessly works across multiple views and documents that opted into this system.
Next, the edit menu has received a major upgrade. It now looks different depending on the input method used. On touch interaction, you get a redesigned menu that is more interactive.
When using a pointer, you get a more full-featured context menu.
To provide both of these experiences in a seamless way, we've introduced UIEditMenuInteraction as a full replacement for the now-deprecated UIMenuController.
There is also new API to insert actions into a text view's menu.
Watch "Adopt desktop class editing interactions" to learn all the details on the new edit menu, and learn how to adopt find interaction for custom views.
There is one visual UI update I'd like to cover. In iOS 16, the sidebar in slide over mode automatically becomes vibrant without any additional code. To achieve this, UIKit manages a set of private views on your behalf.
Those are the new productivity features in UIKit: the new customizable navigation bars, find and replace, editing interactions, as well as the powerful title menu. I am just scratching the surface here. To learn a lot more, check the "Meet desktop class iPad" session, as well as a more in depth "Build a desktop class iPad app," where you'll be walked through improving a sample app with new advanced UIKit features in iOS 16.
Now I'm going to introduce two new controls we've added and discuss some enhancements to UIPageControl.
The inline calendar style of UIDatePicker is now available as a standalone fully-featured component, in the form of UICalendarView. UICalendarView supports different types of selection behaviors, like optional single dates, as well as selecting multiple dates. On top of the available date range, it also supports disabling individual dates from selection.
Moreover, you can annotate individual dates with decorations.
One major difference between UICalendarView and UIDatePicker is that UICalendarView represents dates as NSDateComponents, rather than NSDate. Unlike NSDate, date components are a better, and a more correct representation of a date whereas NSDate is a representation of a point in time.
Because NSDateComponents offer many flexibilities, you should be very explicit about which NSCalendar the components are represented by.
Note that you should not make assumptions about the type of the current calendar. If you need the calendar to be Gregorian, explicitly specify the Gregorian calendar.
To configure a Calendar view like the one shown earlier, first, create the Calendar view and set its delegate. To ensure that the Calendar is backed by the Gregorian NSCalendar, set the calendar property on the calendarView to a Gregorian NSCalendar.
Next, to configure the multi-date selection. Create a UICalendarSelectionMultiDate object, and set the selected dates property on the selection object to existing dates you have from your data model to show in the Calendar view.
Then, set the selection object to the calendar view's selection behavior.
To prevent the selection of individual dates in the Calendar, implement the multiDateSelection:canSelectDate: method from the calendar's selection's delegate to control which dates can be selected.
Dates that cannot be selected will appear greyed out in the calendar view.
To annotate individual dates with decorations, implement the calendar delegate's calendarView:decorationForDateComponents: Method.
For no decorations, simply return nil.
For a default grey circle, return the default decoration.
You can also create image decorations with options to customize its color. And if you need more, use the customView decoration and return your view in the view provider.
Please note that the custom view decorations do not allow interaction and are clipped to the available space.
The page control is also improved. We added the support for custom indicator images for the current page, so you can now choose different images depending on whether the page is selected or not.
Now you can also fully customize both the orientation and the direction of the page control.
Here is an example of configuring a vertical page control whose indicators change between the current versus the non-current pages.
I set the page control's direction to top-to-bottom and set preferred indicator image and preferred current indicator image and that's it! Apple is committed to protecting user privacy and security. In iOS 15, when an application programmatically accessed the pasteboard without using system provided Paste interfaces, a banner would appear to indicate that the pasteboard was accessed.
New to iOS 16, the system behavior has changed. Now, instead of a banner, we will display an alert that asks for permission to use the pasteboard.
System paste interfaces that the users interact with provide implicit access to the pasteboard and will avoid the alert.
If you have custom paste controls, you can replace them with the new UIPasteControl that looks and behaves like a filled UIButton.
It is enabled whenever the pasteboard gets content compatible with the control's paste target.
So those are the new powerful UICalendarView, the improved UIPageControl, as well as the security-oriented UIPasteControl. Go ahead and try them out. Now I'll walk you through some API refinements we've made.
In iOS 15, detents were added to sheets which enabled building flexible and dynamic UIs. In iOS 16, we added support for custom detents so you can make sheets any size.
To take advantage of this feature, use the new ".custom" detent and specify the sheet's height in points in an associated block. You can return a constant value, or a percentage of the maximum detent height.
And you can also give your custom detent an identifier if you need to refer to it from other APIs, for example, to disable dimming above your custom detent.
Note that the value you return from the custom block shouldn't account for the bottom safe area inset. This is so the same calculation works for both floating and edge-attached sheets.
To learn more about customizing sheets with system detents and other options, watch the Customize and resize sheets in UIKit video. The sample code for that video has also been updated to show these new custom detent APIs.
There are new features for SF Symbols in UIKit. Symbols support four rendering modes: monochrome, multicolor, hierarchical, and palette. UIKit would use monochrome rendering by default unless the symbol was configured with a different rendering mode. In iOS 16, UIKit may render individual symbols with a mode other than monochrome if no rendering mode is specified.
Take these device symbols, for example. In iOS 15 and earlier, these symbols use monochrome rendering if no rendering mode is specified.
In iOS 16, these symbols instead default to hierarchical rendering.
Generally, a symbol's default rendering mode is the preferred way to display the symbol. So in this case, you should allow the default hierarchical rendering to take effect. However, monochrome rendering can be explicitly requested with the new UIImage.SymbolConfiguration. preferringMonochrome() API.
UIKit added support for variable symbols, which allows apps to display variations of a symbol based on a value from 0 to 1. Suppose an app wants to depict the current volume level with a symbol. The app can use the speaker.3.wave.fill symbol, which has been updated to support variable rendering. At a value of 0, the speaker waves are faded out, indicating the lowest volume level. As the value increases up to 1, the speaker waves progressively fill in, indicating higher volume levels.
If a symbol supports variable rendering, then apps can request a version of the symbol reflecting a value between 0 and 1.
Using variable symbols is straightforward. You can get the regular non-variable version of a symbol with the standard SF Symbols API on UIImage.
To get a version of that symbol with a particular variable value, simply add the variableValue parameter.
You can even mix variable rendering with other rendering modes, such as palette, to further style the symbol.
Many system symbols now support variable rendering, and apps can update their custom symbols to support variability as well.
To learn how to create custom variable symbols, check out the sessions "Adopt variable color in SF Symbols" and "What's new in SF Symbols 4”.
We've modernized UIKit to work with new Swift Concurrency features, including making immutable types such as UIImage and UIColor conform to Sendable, so you can send them between the MainActor and custom actors without compiler warning.
For example, here we have a custom actor called Processor, and a view controller called ImageViewer which is bound to the MainActor. In the method sendImageForProcessing, the ImageViewer sends an image to the Processor actor for processing, to make it fancy like adding glitter and rainbows to it. This is safe because UIImage is immutable, so Processor has to make new copy to add the rainbows and glitter.
Any code that has a reference to the original image doesn't show these modifications, and a shared state is not unsafely mutated.
Contrast this with UIBezierPath, which is not Sendable because it is mutable.
How cool is it that something that could previously only be expressed in documentation can now be checked by the compiler? To learn more about Sendable and Swift Concurrency, check out "Eliminate data races using Swift Concurrency" and "Visualize and optimize Swift Concurrency" videos.
iOS 16 features new powerful support for external displays. The great news is that you don't have to update your app to take advantage of this, unless you are using old UIScreen APIs.
You can no longer assume your app is on the main screen. Instead, defer to more specific APIs, like trait collection and UIScene APIs, to get the information you need. If your app is still not using UIScene, there's now even more reason to upgrade and to support multiple windows.
Self-sizing cells in UICollectionView and UITableView got a major upgrade. Now cells are also self-resizing! In iOS 16, when the content inside a visible cell changes, the cell will automatically be resized to fit the new content.
This new behavior is enabled by default, and UICollectionView and UITableView each have a new selfSizingInvalidation property that gives you control over this new functionality.
Here is how it works: When selfSizingInvalidation is enabled, cells can request to be resized by their containing collection or table view.
If you're using UIListContentConfiguration to configure cells, the invalidation happens automatically whenever the cell's configuration changes.
For any other cases, you can call the invalidateIntrinsicContentSize method on the cell or its contentView to resize the cell.
By default, cells will be resized with animation, but you can wrap the call to invalidateIntrinsicContentSize inside performWithoutAnimation to resize without animation. UICollectionView and UITableView intelligently coalesce size invalidation from cells into a single update performed at the optimal time.
If you're using Auto Layout in your cells, you can opt-in to an even more comprehensive behavior by choosing enabledIncludingConstraints. This means when a cell detects any auto layout changes inside its contentView, it will automatically call invalidateIntrinsicContentSize on itself so that the containing collection or table view can resize it if necessary. This makes it incredibly easy to have cells that automatically adjust their size in response to content or layout updates.
UIKit is powerful and flexible. You can also take advantage of the expressiveness of implementing UIs using SwiftUI. We've made it much easier to incorporate both frameworks in the same app.
In iOS 16, there is an entirely new way to build cells for your collection and table views using SwiftUI.
This is made possible by a new content configuration type named UIHostingConfiguration. With just one line of code, you can start writing SwiftUI right inside your cells-- no extra views or view controllers needed at all.
Here is a simple custom cell written in SwiftUI using UIHostingConfiguration. It is extremely easily to build this cell.
Not only is this a great way to start integrating SwiftUI into your app, the expressive nature of SwiftUI means there's never been a more powerful way to build custom cells in UIKit. There is a lot more to this topic, so be sure to check out the video "Use SwiftUI with UIKit" to learn more.
There are a couple of small but important changes that you should be aware of. To prevent users from being fingerprinted, UIDevice.name now reports the model name rather than the user's custom device name. Using the customized name now requires getting an entitlement.
Setting UIDevice.orientation is no longer supported. Instead, use UIViewController APIs such as preferredInterfaceOrientation to express the intended orientation of your interface.
What's next? Compile your app using iOS 16 SDK. Test out the new features such as text edit menus and find and replace. Adopt the new UIKit APIs to use new enhanced controls and productivity features. And experiment with the new exciting ways to incorporate SwiftUI in your UIKit app. Thank you. ♪ ♪