如何更改 UIPopoverPresentationController 后面的叠加层的不透明度?

How can I change the opacity of the overlay behind UIPopoverPresentationController?

我正在使用 UIPopoverPresentationController 在 iOS 应用程序中显示弹出窗口。当它出现时,我想调暗弹出窗口后面的背景。我怎样才能做到这一点?某处是否有 API,或者当我显示弹出窗口时我是否必须在主视图上覆盖某些内容?

popoverController.contentViewController.view.alpha = 0.5;

Transparent UIPopover

我最终通过在显示弹出窗口时将自己的覆盖层放在主视图上来解决这个问题。我之所以能够轻松做到这一点,是因为我通过一个单例协调器 class 完成所有弹出窗口,我的根视图控制器不是导航控制器,而且我可以在任何地方轻松访问它。我还必须创建一个 UINavigationController 的 subclass 子 UINavigationController ,以便我可以覆盖 dismissViewControllerAnimated:completion: 并通知协调员,以便它删除覆盖( didDismiss 委托方法不当以编程方式关闭弹出窗口时不会调用它)。

一种直接的非侵入式解决方案:showing/hiding 通过 UIPopoverPresentationControllerDelegate 建立叠加视图,如下所示:(在 Swift 2.0 中)

class PopoverDelegate: NSObject, UIPopoverPresentationControllerDelegate {
    var overlay: UIView?

    dynamic func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return .None
    }

    dynamic func presentationController(presentationController: UIPresentationController, willPresentWithAdaptiveStyle style: UIModalPresentationStyle, transitionCoordinator: UIViewControllerTransitionCoordinator?) {
        // add a semi-transparent view to parent view when presenting the popover
        let parentView = presentationController.presentingViewController.view

        let overlay = UIView(frame: parentView.bounds)
        overlay.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
        parentView.addSubview(overlay)

        let views: [String: UIView] = ["parentView": parentView, "overlay": overlay]

        parentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[overlay]|", options: [], metrics: nil, views: views))
        parentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[overlay]|", options: [], metrics: nil, views: views))

        overlay.alpha = 0.0

        transitionCoordinator?.animateAlongsideTransition({ _ in
            overlay.alpha = 1.0
        }, completion: nil)

        self.overlay = overlay
    }

    deinit {
        // remove the overlay with animation.
        // the delegate method popoverPresentationControllerDidDismissPopover(_:) is not called 
        // if the popover is dismissed programmatically, 
        // so the removal goes here.

        guard let overlay = overlay else {
            return
        }
        dispatch_async(dispatch_get_main_queue()) {
            UIView.animateWithDuration(0.2, animations: {
                overlay.alpha = 0.0
                }, completion: { _ in
                    overlay.removeFromSuperview()
            })
        }
    }

}

然后当弹出框即将显示时,将 UIPopoverPresentationController 的委托设置为 PopoverDelegate 的实例,弹出框后面的背景会变暗。

通过 UIPopoverPresentationController 呈现并使用其委托方法更改 containerView 属性:

- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController {
//
popoverPresentationController.containerView.backgroundColor = [UIColor colorWithWhite:0 alpha:.72];

在swift 3 你可以访问叠加层:

extension UIPopoverPresentationController {

    var dimmingView: UIView? {
       return value(forKey: "_dimmingView") as? UIView
    }
}

将控制器设置为弹出模式后

controller.modalPresentationStyle = UIModalPresentationStyle.popover
controller.popoverPresentationController.dimmingView.backgroundColor = UIColor.black.withAlphaComponent(0.4)

我刚刚创建了我的视图控制器,设置了弹出窗口样式然后呈现它,在完成回调中设置了背景颜色(因为此时 containerView 将是非零的)。适用于 Swift 4+.

let myViewController: MyViewController = MyViewController()
myViewController.modalPresentationStyle = UIModalPresentationStyle.popover

if let presentationController: UIPopoverPresentationController = myViewController.popoverPresentationController {
    presentationController.delegate = self.mainViewController
    presentationController.sourceView = sourceView
    presentationController.sourceRect = sourceRect
    self.mainViewController.present(myViewController, animated: false, completion: {
        presentationController.containerView?.backgroundColor = UIColor.white.withAlphaComponent(0.5)
    })
}