8

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 this? Is there an API for it somewhere, or am I going to have to overlay something on the main view when I present the popover?

Ortwin Gentz
  • 52,648
  • 24
  • 135
  • 213
Tom Hamming
  • 10,577
  • 11
  • 71
  • 145

6 Answers6

9

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)
Carlos Chaguendo
  • 2,895
  • 19
  • 24
7

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];
Jim75
  • 737
  • 8
  • 13
2

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.

eternity
  • 473
  • 5
  • 8
1

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).

Tom Hamming
  • 10,577
  • 11
  • 71
  • 145
0

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)
    })
}
wildcat12
  • 975
  • 6
  • 13
-3
popoverController.contentViewController.view.alpha = 0.5;

Transparent UIPopover

Community
  • 1
  • 1
Cristiano Alves
  • 233
  • 1
  • 13