Presenting a UIAlertController properly on an iPad using iOS 8
You can present a UIAlertController
from a popover by using UIPopoverPresentationController
.
In Obj-C:
UIViewController *self; // code assumes you're in a view controllerUIButton *button; // the button you want to show the popup sheet fromUIAlertController *alertController;UIAlertAction *destroyAction;UIAlertAction *otherAction;alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];destroyAction = [UIAlertAction actionWithTitle:@"Remove All Data" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { // do destructive stuff here }];otherAction = [UIAlertAction actionWithTitle:@"Blah" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { // do something here }];// note: you can control the order buttons are shown, unlike UIActionSheet[alertController addAction:destroyAction];[alertController addAction:otherAction];[alertController setModalPresentationStyle:UIModalPresentationPopover];UIPopoverPresentationController *popPresenter = [alertController popoverPresentationController];popPresenter.sourceView = button;popPresenter.sourceRect = button.bounds;[self presentViewController:alertController animated:YES completion:nil];
Editing for Swift 4.2, though there are many blogs available for the same but it may save your time to go and search for them.
if let popoverController = yourAlert.popoverPresentationController { popoverController.sourceView = self.view //to set the source of your alert popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0) // you can set this as per your requirement. popoverController.permittedArrowDirections = [] //to hide the arrow of any particular direction}
On iPad the alert will be displayed as a popover using the new UIPopoverPresentationController, it requires that you specify an anchor point for the presentation of the popover using either a sourceView and sourceRect or a barButtonItem
- barButtonItem
- sourceView
- sourceRect
In order to specify the anchor point you will need to obtain a reference to the UIAlertController's UIPopoverPresentationController and set one of the properties as follows:
alertController.popoverPresentationController.barButtonItem = button;
sample code:
UIAlertAction *actionDelete = nil;UIAlertAction *actionCancel = nil;// create action sheetUIAlertController *alertController = [UIAlertController alertControllerWithTitle:actionTitle message:nil preferredStyle:UIAlertControllerStyleActionSheet];// Delete ButtonactionDelete = [UIAlertAction actionWithTitle:NSLocalizedString(@"IDS_LABEL_DELETE", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { // Delete // [self deleteFileAtCurrentIndexPath]; }];// Cancel ButtonactionCancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"IDS_LABEL_CANCEL", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { // cancel // Cancel code }];// Add Cancel action[alertController addAction:actionCancel];[alertController addAction:actionDelete];// show action sheetalertController.popoverPresentationController.barButtonItem = button;alertController.popoverPresentationController.sourceView = self.view;[self presentViewController:alertController animated:YES completion:nil];
In Swift 2, you want to do something like this to properly show it on iPhone and iPad:
func confirmAndDelete(sender: AnyObject) { guard let button = sender as? UIView else { return } let alert = UIAlertController(title: NSLocalizedString("Delete Contact?", comment: ""), message: NSLocalizedString("This action will delete all downloaded audio files.", comment: ""), preferredStyle: .ActionSheet) alert.modalPresentationStyle = .Popover let action = UIAlertAction(title: NSLocalizedString("Delete", comment: ""), style: .Destructive) { action in EarPlaySDK.deleteAllResources() } let cancel = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .Cancel) { action in } alert.addAction(cancel) alert.addAction(action) if let presenter = alert.popoverPresentationController { presenter.sourceView = button presenter.sourceRect = button.bounds } presentViewController(alert, animated: true, completion: nil)}
If you don't set the presenter, you will end up with an exception on iPad in -[UIPopoverPresentationController presentationTransitionWillBegin]
with the following message:
Fatal Exception: NSGenericException Your application has presented a UIAlertController (<UIAlertController: 0x17858a00>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.