I\'m using UIPopoverPresentationController
to present popovers in an iOS app. I want to dim the background behind the popover when it comes up. How can I do thi
popoverController.contentViewController.view.alpha = 0.5;
Transparent UIPopover
A drop-in non-intrusive solution: showing/hiding up an overlay view via UIPopoverPresentationControllerDelegate
, like this: (in 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()
})
}
}
}
Then when a popver is about to be presented, set the delegate of UIPopoverPresentationController
to an instance of PopoverDelegate
, and you get a dimmed background behind the popover.
in swift 3 you can access the overlay:
extension UIPopoverPresentationController {
var dimmingView: UIView? {
return value(forKey: "_dimmingView") as? UIView
}
}
After setting your controller to popover mode
controller.modalPresentationStyle = UIModalPresentationStyle.popover
controller.popoverPresentationController.dimmingView.backgroundColor = UIColor.black.withAlphaComponent(0.4)
Present via UIPopoverPresentationController and use its delegate method to change the containerView attributes:
- (void)prepareForPopoverPresentation:(UIPopoverPresentationController *)popoverPresentationController {
//
popoverPresentationController.containerView.backgroundColor = [UIColor colorWithWhite:0 alpha:.72];
I ended up solving this by putting my own overlay over my main view when I present the popover. I was able to do this easily because I do all my popovers through one singleton coordinator class, my root view controller isn't a navigation controller, and I can get to it easily everywhere. I also had to create a subclass of UINavigationController
everywhere I presented one in a popover so I could override dismissViewControllerAnimated:completion:
and notify the coordinator so it removed the overlay (the didDismiss delegate method doesn't get called when the popover is dismissed programmatically).
I just created my view controller, set the popover style and then presented it, setting the background color in the completion callback (because the containerView will be non-nil at that point). Works well with 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)
})
}