iOS 15 added UISheetPresentationController
which allows you to implement a half-height sheet by setting sheetPresentationController
's detents to [.medium()]
. You can then set the largestUndimmedDetentIdentifier
to .medium
to allow interacting with the presenting view controller and the sheet so you can achieve an interface similar to Maps and Stocks.
My question is, how could you detect when an undimmed sheet is presented and get its height in order to inset content in the underlying screen(s). For example, I want to add content insets to my table view so that you can scroll to see all cells. Currently, the sheet covers up the bottom cells making it impossible to interact with those - you can only tap the ones that lie above where the sheet rests.
To do this, set the sheetPresentationController.delegate
and adopt the UISheetPresentationControllerDelegate
protocol. This will inform you when it will present and did dismiss. You can then animate moving your content as appropriate in an animateChanges
block. Here's an example:
extension ViewController: UISheetPresentationControllerDelegate {
func presentationController(_ presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?) {
updateContentsForPresentedSheet(isPresented: true)
(presentationController as? UISheetPresentationController)?.animateChanges {
view.layoutIfNeeded()
}
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
updateContentsForPresentedSheet(isPresented: false)
(presentationController as? UISheetPresentationController)?.animateChanges {
view.layoutIfNeeded()
}
}
}
private func updateContentsForPresentedSheet(isPresented: Bool) {
bottomConstraint.constant = isPresented ? view.bounds.height / 2 : 0
}
Note the medium detent height is seemingly indeterminate but close to half the screen height. If you need to precisely adjust your interface, iOS 16 adds the ability to provide a custom detent where you specify the exact height desired. Here's an example:
viewController.sheetPresentationController?.detents = [.custom(resolver: { [weak self] context in
guard let self else { return nil }
// Note the system automatically accommodates the safe area so we'll subtract those insets
return self.view.bounds.height / 2 - self.view.safeAreaInsets.bottom
})]