UIAlertController handle dismiss upon click outside (IPad)

Previous to iOS8 we used the UIActionSheet for showing alert and now we need to use the UIAlertController.

When we used the UIActionSheet we could easily handle situations where the user clicked outside the pop up (which means he want to cancel the operation) by comparing the clickedButtonAtIndex to the cancelButtonIndex – if the user indeed pressed outside the popup we got the cancel button index in this function.

  • Check on UIAlertController TextField for enabling the button
  • How to use UITextView in UIAlertController
  • Change title and message font of alert using UIAlertController in Swift
  • Presenting a view controller modally from an action sheet's delegate in iOS8 - iOS10
  • How to use UIAlertController to replace UIActionSheet?
  • How to display activity indicator in center of UIAlertController?
  • How can we handle these situations with the new UIAlertController? I tried to use the “completion” block but it doesn’t have any context. Is there an easy way to handle this? (other than “saving” the actions states in some general variable).

    3 Solutions Collect From Internet About “UIAlertController handle dismiss upon click outside (IPad)”

    You can add an action with style:UIAlertActionStyleCancel and the handler for this action is called when the user taps outside the popup.

    if ([UIAlertController class]) {
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert Title" message:@"A Message" preferredStyle:UIAlertControllerStyleActionSheet];
    
        [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
            NSLog(@"User clicked button called %@ or tapped elsewhere",action.title);
        }]];
    
        [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            NSLog(@"User clicked button called %@",action.title);
        }]];
    
        [alertController addAction:[UIAlertAction actionWithTitle:@"Other" style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
            NSLog(@"User clicked button called %@",action.title);
        }]];
    
        UIControl *aControl = (UIControl *) sender;
        CGRect frameInView = [aControl convertRect:aControl.bounds toView:self.view];
        alertController.popoverPresentationController.sourceRect = frameInView;
        alertController.popoverPresentationController.sourceView = self.view;
        alertController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
        [self presentViewController:alertController animated:YES completion:nil];
    }
    

    The solution which works for UIAlertController with alert style. Just needed to add gesture recognizer to alertController superview.

        [self presentViewController: alertController
                       animated: YES
                     completion:^{
                         alertController.view.superview.userInteractionEnabled = YES;
                         [alertController.view.superview addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(alertControllerBackgroundTapped)]];
                     }];
    
    - (void)alertControllerBackgroundTapped
    {
        [self dismissViewControllerAnimated: YES
                                 completion: nil];
    }
    

    UITapGestureRecognizer didn’t work for me so I’ve used this way:

    func addDismissControl(_ toView: UIView) {
        let dismissControl = UIControl()
        dismissControl.addTarget(self, action: #selector(self.dismissAlertController), for: .touchDown)
        dismissControl.frame = toView.superview?.frame ?? CGRect.zero
        toView.superview?.insertSubview(dismissControl, belowSubview: toView)
    }
    
    func dismissAlertController() {
        self.dismiss(animated: true, completion: nil)
    }
    
    func presentAlertController(title: String?, message: String?, preferredStyle: UIAlertControllerStyle,  handler: ((UIAlertAction) -> Swift.Void)? = nil, completion: (() -> Swift.Void)? = nil) {
    
        let alertController = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet)
        alertController.addAction(UIAlertAction(title: "OK", style: .default) { (alertAction) -> Void in
            handler?(alertAction)
        })
    
        self.present(alertController, animated: true, completion: {
            self.addDismissControl(alertController.view)
            completion?()
        })
    }
    
    func someWhereInYourViewController() {
        // ...
        presentAlertController(title: "SomeTitle", message: "SomeMessage", preferredStyle: .actionSheet, handler: { (alertAction) -> Void in
            //do some action
        }, completion: {
            //do something after presentation
        })
        // ...
    }