Skip to main content

The ABC of Making a UIAlertViewController Popover in Swift (Xcode 7 beta 2; iOS 9)


Last time we looked at making a UIImagePickerController popover, and this time we do something very similar but slightly different. We start by creating a UIAlertController instance:
let distributionAlertController = UIAlertController(title: "Distribution", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
Note here the use of preferred style UIAlertControllerStyle.ActionSheet rather than .Alert. Next we want to add an action to the alert, which happens like this:
// create the action
let fill = UIAlertAction(title: "Fill", style: UIAlertActionStyle.Default, handler: {[unowned self] a in self.stackView.distribution = UIStackViewDistribution.Fill; self.distributionAlertController.dismissViewControllerAnimated(true, completion: nil)})
// add the action
distributionAlertController.addAction(fill)
You can add as many actions as you like (within reason of course!).

Note: The example assumes the use of a UIStackView called stackView.

Calling the alert

And finally we want to call the alert from a button, and then access the UIPopoverPresentationController instance to set the anchor of the popover:
// present view controller
presentViewController(distributionAlertController, animated: true, completion: nil)

// set button to be origin of popover
let presentationController = distributionAlertController.popoverPresentationController
presentationController?.barButtonItem = sender as? UIBarButtonItem
It is important to observe that the presentation happens first and the popoverPresentationController retrieved and altered following this (as with the UIImagePickerController examined in the previous post). It is equally important to note that a bar button item is only one of the choices the positioning the anchor of the popover. The other option is to declare a sourceRect (in combination with a sourceView).

Note: The code assumes that it is inside a method that is called by a button.

A little extra

Perhaps we might want to figure out what the current distribution is and have this appear as the message inside the alert:
@IBAction func distributeContents(sender: AnyObject) {
        
    switch stackView.distribution {
        case UIStackViewDistribution.Fill:
                distributionAlertController.message = "Current: Fill"
        case UIStackViewDistribution.FillEqually:
            distributionAlertController.message = "Current: Fill Equally"
        case UIStackViewDistribution.FillProportionally:
            distributionAlertController.message = "Current: Fill Proportionally"
        case UIStackViewDistribution.EqualSpacing:
            distributionAlertController.message = "Current: Equal Spacing"
        case UIStackViewDistribution.EqualCentering:
            distributionAlertController.message = "Current: Equal Centering"
    }
        
    self.presentViewController(distributionAlertController, animated: true, completion: nil)
    let presentationController = distributionAlertController.popoverPresentationController
    presentationController?.barButtonItem = sender as? UIBarButtonItem
}
Note: in the first piece of code we created the UIAlertController locally but it most like wants to be a global within your view controller in real use.

Conclusion

Now you have a popover on the iPad and the equivalent modal presentation on the iPhone by simply implementing this code. And no more need for deprecated popover methods.

If you want a regular alert then simply set the UIAlertController style to Alert for the UIAlertController and remove the code that reads:
// present view controller
// set button to be origin of popover
let presentationController = distributionAlertController.popoverPresentationController
presentationController?.barButtonItem = sender as? UIBarButtonItem
instead using only,
// present view controller
presentViewController(distributionAlertController, animated: true, completion: nil)
on its own.

Comments