2021 SwiftUI & UI Frameworks
WWDC21 · 12 min · SwiftUI & UI Frameworks
Customize and resize sheets in UIKit
Discover how you can create a layered and customized sheet experience in UIKit. We’ll explore how you can build a non-modal experience in your app to allow interaction with content both in a sheet and behind the sheet at the same time. We’ll also take you through sheet size customization, revealing or hiding grabber controls, and adapting between popovers and customized sheets in your app. To get the most out of this session, we recommend watching the Presentations portion of “Modernizing Your UI for iOS 13” from WWDC19 beginning at 9:45.
Watch at developer.apple.com ↗Code shown on screen · 15 snippets
Get a sheet
if let sheet = viewController.sheetPresentationController {
// Customize the sheet
}
present(viewController, animated: true) Detents (large only)
if let sheet = picker.sheetPresentationController {
sheet.detents = [.large()]
}
present(picker, animated: true) Detents (medium and large)
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
}
present(picker, animated: true) Detents (medium only)
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium()]
}
present(picker, animated: true) Present image picker in a standard sheet
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
dismiss(animated: true)
} Present at medium detent, and don’t dismiss automatically
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
}
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
} Prevent scrolling from expanding the sheet
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
}
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
} Select medium detent when a photo is picked
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
}
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
if let sheet = picker.sheetPresentationController {
sheet.selectedDetentIdentifier = .medium
}
} Animate selection of medium detent
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
}
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
if let sheet = picker.sheetPresentationController {
sheet.animateChanges {
sheet.selectedDetentIdentifier = .medium
}
}
} Remove dimming at medium detent
func showImagePicker() {
let picker = PHPickerViewController()
picker.delegate = self
if let sheet = picker.sheetPresentationController {
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
sheet.smallestUndimmedDetentIdentifier = .medium
}
present(picker, animated: true)
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
if let sheet = picker.sheetPresentationController {
sheet.animateChanges {
sheet.selectedDetentIdentifier = .medium
}
}
} iPhone in landscape
if let sheet = fontPicker.sheetPresentationController {
sheet.prefersEdgeAttachedInCompactHeight = true
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
present(fontPicker, animated: true) Show a grabber
if let sheet = fontPicker.sheetPresentationController {
sheet.prefersGrabberVisible = true
}
present(fontPicker, animated: true) Customize the corner radius
if let sheet = fontPicker.sheetPresentationController {
sheet.preferredCornerRadius = 20.0
}
present(fontPicker, animated: true) Adapt a popover to a customized sheet
func showImagePicker(_ sender: UIBarButtonItem) {
let picker = PHPickerViewController()
picker.delegate = self
picker.modalPresentationStyle = .popover
if let popover = picker.popoverPresentationController {
popover.barButtonItem = sender
let sheet = popover.adaptiveSheetPresentationController
sheet.detents = [.medium(), .large()]
sheet.prefersScrollingExpandsWhenScrolledToEdge = false
sheet.smallestUndimmedDetentIdentifier = .medium
}
present(picker, animated: true)
} Be consistent when using adaptiveSheetPresentationController
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
// assign result to imageView.image
if let sheet = picker.popoverPresentationController?.adaptiveSheetPresentationController {
sheet.animateChanges {
sheet.selectedDetentIdentifier = .medium
}
}
} Resources
Related sessions
-
24 min -
18 min -
50 min