iosswiftpopoveruimodalpresentationstyleuipopoverpresentationcontroller

adaptivePresentationStyle not Triggering for UIPopoverPresentationControllerDelegate on Compact (iPhone) Devices


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:

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
    }
}

Solution

  • 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:

    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
            }
        }
    }