adaptivePresentationStyle not Triggering for UIPopoverPresentationControllerDelegate on Compact (iPhone) Devices

时间:2019-03-17 23:03:07

标签: ios swift popover uimodalpresentationstyle uipopoverpresentationcontroller

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:

  • The viewControllerForAdaptivePresentationStyle does get called if an @objc marker is added before it, but that doesn't work for the others.
  • Xcode is giving a warning for each one: Instance method ... nearly matches optional requirement ... of protocol 'UIAdaptivePresentationControllerDelegate'; however, the method signature is a 100% match. Not sure if this is an instance of this bug, which some say still exists in Xcode 10.1.

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

1 个答案:

答案 0 :(得分:0)

感谢Paulw11确认问题是由在UIViewController扩展中实施代码引起的。这导致了奇怪的行为,从而使代码没有像往常一样被调用。

当迁移到UIViewController的共享子类时,以下问题已全部解决:

  • 从未调用过adaptivePresentationStyle方法。
  • 只有在viewControllerForAdaptivePresentationStyle标记之后才调用@objc方法。
  • 提供实例方法的
  • Xcode ...与协议'UIAdaptivePresentationControllerDelegate'错误的可选要求...几乎匹配。

对于寻求相同功能的任何人,正确的代码如下。

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