I'm attempting to display one UIViewController
as a popover from another. For that, I've established the following...
func showPopover(ofViewController popoverViewController: UIViewController, sender: UIView) {
popoverViewController.modalPresentationStyle = .popover
popoverViewController.popoverPresentationController?.sourceView = sender
popoverViewController.popoverPresentationController?.sourceRect = sender.bounds
popoverViewController.popoverPresentationController?.delegate = self
self.present(popoverViewController, animated: true, completion: nil)
}
However, the new VC always shows as a full-screen, modal presentation on compact devices, rather than an actual popover. Based on what I've read here & here, that's normal behaviour, but should be customizable through delegation.
I've declared the presenting VC as implementing UIPopoverPresentationControllerDelegate
, set it as the delegate, and implemented the required methods; however, the delegation methods are never getting called. This means the 'popover' is still getting shown modally, regardless.
Any advice would be welcome.
Some other callouts:
viewControllerForAdaptivePresentationStyle
does get called if an @objc
marker is added before it, but that doesn't work for the others.Thanks.
Delegate functions implemented:
func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.popover
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return UIModalPresentationStyle.popover
}
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
switch style {
case .fullScreen: // Configuration for full-screen
default: return controller.presentedViewController
}
}
Thanks to Paulw11 for confirming that the problem was caused by implementing the code in an extension of UIViewController
. This was resulting in strange behaviours, whereby the code wasn't being called as usual.
When migrated to a shared subclass of UIViewController
, the following problems were all resolved:
adaptivePresentationStyle
method never being called.viewControllerForAdaptivePresentationStyle
method only being called if preceded by the @objc
tag.Corrected code is as follows, for anyone seeking the same functionality.
class CustomViewController: UIViewController {
func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) {
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
if let popoverController = popoverViewController.popoverPresentationController {
popoverController.delegate = self
popoverController.sourceView = originView
popoverController.sourceRect = originView.bounds
popoverController.backgroundColor = popoverViewController.view.backgroundColor
popoverController.permittedArrowDirections = UIPopoverArrowDirection.any
}
self.present(popoverViewController, animated: true)
}
}
extension CustomViewController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
//return UIModalPresentationStyle.fullScreen
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
if traitCollection.horizontalSizeClass == .compact {
return UIModalPresentationStyle.none
//return UIModalPresentationStyle.fullScreen
}
//return UIModalPresentationStyle.fullScreen
return UIModalPresentationStyle.none
}
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
switch style {
case .fullScreen: // Configuration for full-screen
default:
return controller.presentedViewController
}
}
}