Highlight
iOS 16 adds a desktop-level navigation bar to UIKit,
UICalendarView、UIPasteControl, custom sheet detent, self-resizing cells andUIHostingConfiguration, allowing iPad, iPhone and Mac Catalyst apps to use system APIs to complete more productivity interfaces.
Core Content
The theme of UIKit in iOS 16 is clear: integrate many tasks that previously required custom controls, handwritten layouts or platform branches into the system API.
Document apps are the first category of beneficiaries. The navigation bar adds two styles, browser and editor, and supports customizable central tool items, automatic overflow menus, title menus, and Mac Catalyst andNSToolbarAutomatic integration of (01:22).
Text editing is also closer to the desktop experience. Built-inUITextViewandWKWebViewJust turn on a flag to enable find and replace; oldUIMenuControllerquiltUIEditMenuInteractionInstead, use the same mechanism to overlay the touch menu and pointer context menu (03:29).
At the control level, Apple changed inline calendar fromUIDatePickersplit into independentUICalendarView. It supports single selection, multiple selection, disabling single date and date decoration.UIPageControlIt also supports customizing the indicator images of the current page and non-current page, and can configure the direction (06:13).
There are two other types of changes that affect day-to-day code.UISheetPresentationControllerSupports custom detent, the cell can automatically recalculate the size after the content changes, and the UIKit cell can also be used directlyUIHostingConfigurationWriting SwiftUI Content (12:03, [19:05](https://developer.apple.com/v ideos/play/wwdc2022/10068/?time=1145), 21:25).
Detailed Content
Use UCalendarView to create a multi-selectable calendar
UICalendarViewUse date componentDateComponentsRepresent dates to avoid mistaking calendar dates for time pointsDate. This is an important difference. “June 10” in the calendar needs to be combined with a specific calendar to make sense. Therefore, session reminds you: if your business requires Gregorian calendar, set it explicitly (07:00).
// Configuring a calendar view with multi-date selection
let calendarView = UICalendarView()
calendarView.delegate = self
calendarView.calendar = Calendar(identifier: .gregorian)
view.addSubview(calendarView)
let multiDateSelection = UICalendarSelectionMultiDate(delegate: self)
multiDateSelection.selectedDates = myDatabase.selectedDates()
calendarView.selectionBehavior = multiDateSelection
func multiDateSelection(
_ selection: UICalendarSelectionMultiDate,
canSelectDate dateComponents: DateComponents
) -> Bool {
return myDatabase.hasAvailabilities(for: dateComponents)
}
Key points:
UICalendarView()Create an independent calendar control and no longer bind the inline calendar toUIDatePickersuperior. -calendarView.delegate = selfLet the current object be responsible for providing callbacks such as date decoration. -calendarView.calendar = Calendar(identifier: .gregorian)Explicitly use the Gregorian calendar to avoid relying on the user’s current calendar type. -UICalendarSelectionMultiDate(delegate: self)Create multiple date selection behaviors. -selectedDatesRestore selected dates from the data model to make the initial state of the calendar consistent with business data. -calendarView.selectionBehavior = multiDateSelectionAttach the selection rules to the calendar control. -canSelectDatereturnfalse, the date will be grayed out and cannot be selected by the user.
Decorate calendar dates
Calendars are not just responsible for picking dates. It can also display the status of a certain day, such as busy, traveling, and gathering. The approach is to realizecalendarView(_:decorationFor:), returning different values according to the data modelUICalendarView.Decoration(09:07)。
// Configuring Decorations
func calendarView(
_ calendarView: UICalendarView,
decorationFor dateComponents: DateComponents
) -> UICalendarView.Decoration? {
switch myDatabase.eventType(on: dateComponents) {
case .none:
return nil
case .busy:
return .default()
case .travel:
return .image(airplaneImage, color: .systemOrange)
case .party:
return .customView {
MyPartyEmojiLabel()
}
}
}
Key points:
decorationFor dateComponentsUse the date component to query business status. -return nilIndicates that there is no decoration on this day. -.default()Displays the system default gray dot. -.image(airplaneImage, color: .systemOrange)Use pictures and colors to express travel status. -.customView { MyPartyEmojiLabel() }Provide custom views for special states.- transcript clearly states that custom decoration views are not interactive and will be cropped to fit the available space.
Customize the direction and indicator of UIPageControl
UIPageControliOS 16 supports two previously common customization requirements: vertical page indicators, and using different images for the current page and non-current pages (09:53).
// Vertical page control with custom indicators
pageControl.direction = .topToBottom
pageControl.preferredIndicatorImage = UIImage(systemNamed: "square")
pageControl.preferredCurrentIndicatorImage = UIImage(systemNamed: "square.fill")
Key points:
direction = .topToBottomChange the page control to arrange it from top to bottom. -preferredIndicatorImageSet the indicator image for normal pages. -preferredCurrentIndicatorImageSet the indicator image for the current page.- Example using SF Symbols
squareandsquare.fill, there is no need to draw points yourself or maintain the selected state.
Use custom detent to control sheet height
With the introduction of sheet detent in iOS 15, developers can switch between the system’s medium and large sizes. iOS 16 added.customdetent, you can directly return a fixed height, or calculate the ratio based on the maximum height (12:03).
// Create a custom detent
sheet.detents = [
.large(),
.custom { _ in
200.0
}
]
Key points:
sheet.detentsDefines the set of heights at which the sheet can be docked. -.large()Preserves the large size state of the system. -.custom { _ in 200.0 }Add a 200 point high custom state.- Session reminder, the closure return value does not need to calculate the bottom safe area inset, the system will handle the difference between floating and edge-attached sheets.
If the height needs to be related to the container space, you can readcontext.maximumDetentValue(12:38)。
// Create a custom detent
sheet.detents = [
.large(),
.custom { context in
0.3 * context.maximumDetentValue
}
]
Key points:
contextProvides the maximum detent height in the current environment. -0.3 * context.maximumDetentValueIndicates that the custom detent uses 30% of the maximum height.- This writing method is more suitable for horizontal and vertical screen switching and different device sizes than fixed point.
When the detent needs to be referenced by other APIs, first define the identifier and then pass it to.custom(12:42)。
// Define a custom identifier
extension UISheetPresentationController.Detent.Identifier {
static let small = UISheetPresentationController.Detent.Identifier("small")
}
// Assign identifier to custom detent
sheet.detents = [
.large(),
.custom (identifier: .small) { context in
0.3 * context.maximumDetentValue
}
]
// Disable dimming above the custom detent
sheet.largestUndimmedDetentIdentifier = .small
Key points:
- extension
UISheetPresentationController.Detent.Identifier, give the custom detent a stable name. -.custom(identifier: .small)Create custom detents that can be referenced. -largestUndimmedDetentIdentifier = .smallLet the sheet stop in the small state and below without masking the content behind it.
Let the cell automatically adjust its height as the content changes
Previously, the trouble with dynamic height cells was after updating. When the content changes, the cell does not necessarily recalculate the height immediately. In iOS 16,UICollectionViewandUITableViewThe cell supports self-resizing: when the internal content of the visible cell changes, the container can automatically trigger size updates (19:05).
This part of the session does not provide complete code snippets, but clearly provides the API entry:
collectionView.selfSizingInvalidation = .enabled
cell.contentView.invalidateIntrinsicContentSize()
Key points:
selfSizingInvalidationyesUICollectionViewandUITableViewThe new attribute on is used to control the size invalidation behavior after the cell content changes.- use
UIListContentConfigurationWhen configuring a cell, configuration changes will automatically trigger invalidation. - Other scenarios can be done in cell or
contentViewcall oninvalidateIntrinsicContentSize(). - If using Auto Layout, you can choose
enabledIncludingConstraints, so that changes in the internal constraints of the content view also trigger size updates. - When you need to update without animation, wrap the invalidation call in
performWithoutAnimationmiddle.
Write SwiftUI directly in UIKit cell
When UIKit and SwiftUI are mixed, a common practice in the past was to plug in a hosting controller or hosting view. iOS 16 addedUIHostingConfiguration, allowing collection view and table view cell to describe content directly using SwiftUI (21:43).
cell.contentConfiguration = UIHostingConfiguration {
VStack {
Image(systemName: "wand.and.stars")
.font(.title)
Text("Like magic!")
.font(.title2).bold()
}
.foregroundStyle(Color.purple)
}
Key points:
cell.contentConfiguration = UIHostingConfiguration { ... }Use SwiftUI content as the cell’s content configuration. -VStackResponsible for vertically arranging icons and text. -Image(systemName: "wand.and.stars")Use SF Symbol. -.font(.title)Set the icon font size. -Text("Like magic!")Display text. -.font(.title2).bold()Set text style. -.foregroundStyle(Color.purple)Sets a purple foreground style to the entire SwiftUI content.- transcript emphasizes that this approach does not require an additional view or view controller.
Core Takeaways
-
What to do: Add a desktop-level title menu to your document editing app. Why it’s worth doing: The navigation title menu of iOS 16 can automatically display standard items such as duplicate, move, rename, export, and print. How to start: Use browser or editor navigation style, and implement the corresponding delegate method; add custom menu items when additional commands are needed.
-
What to do: Make a scheduling interface that allows you to select multiple available dates. Why it’s worth doing:
UICalendarViewSupports multiple selection, disabling single date and date decoration. How to get started: CreateUICalendarSelectionMultiDate,usecanSelectDateFilter out-of-stock dates before usingdecorationForMark busy, traveling or special events. -
What to do: Make the bottom sheet into a lightweight control panel with 30% height. Why it’s worth doing: Custom detent can be calculated based on the maximum height, and is no longer limited to the system’s medium and large. How to start: Use
.custom { context in 0.3 * context.maximumDetentValue }Create a detent and define an identifier for it if needed. -
What to do: Let the comment, rich text or setting item cell automatically become taller after the content changes. Why it’s worth doing: iOS 16’s self-resizing cells will merge size invalidation requests and update the table view or collection view when appropriate. How to get started: Check
selfSizingInvalidation,useUIListContentConfigurationPriority is given to relying on automatic invalidation; it is called when the custom content changesinvalidateIntrinsicContentSize()。 -
What to do: Gradually introduce SwiftUI cells into the existing UIKit list. Why it’s worth doing:
UIHostingConfigurationIt can be used directly as the content configuration of the cell without the need for an additional hosting controller. How to start: Start with a visually independent cell and putcell.contentConfigurationReplace withUIHostingConfiguration { ... }。
Related Sessions
- Build a desktop-class iPad app — Continue to integrate the navigation bar, toolbar and document workflow mentioned in this session into a complete iPad app.
- Adopt desktop-class editing interactions — In-depth explanation
UIEditMenuInteraction, find interaction, and a desktop-level editing experience. - Bring multiple windows to your SwiftUI app — Supplement the multi-window capabilities of SwiftUI app on iPadOS.
- Adopt Variable Color in SF Symbols — Learn more about SF Symbols’ variable color and rendering updates in iOS 16.
Comments
GitHub Issues · utterances