How to dismiss UIAlertController when tap outside the UIAlertController?

IosUialertviewUialertcontroller

Ios Problem Overview


How to dismiss UIAlertController when tap outside the UIAlertController?

I can add a UIAlertAction of style UIAlertActionStyleCancel to dismiss the UIAlertController.

But I want to add the function that when user tap outside the UIAlertController the UIAlertController will dismiss. How to do that? Thank you.

Ios Solutions


Solution 1 - Ios

Add a separate cancel action with style UIAlertActionStyleCancel. So that when user taps outside, you would get the callback.

Obj-c

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert Title" message:@"A Message" preferredStyle:UIAlertControllerStyleActionSheet];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
 // Called when user taps outside
}]];

Swift 5.0

let alertController = UIAlertController(title: "Alert Title", message: "A Message", preferredStyle: .actionSheet)             
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { 
    action in
         // Called when user taps outside
}))

Solution 2 - Ios

If you are targeting devices having iOS > 9.3 and using Swift and preferredStyle is Alert you can use snippet as below:

func showAlertBtnClicked(sender: UIButton) {
    let alert = UIAlertController(title: "This is title", message: "This is message", preferredStyle: .Alert)
    self.presentViewController(alert, animated: true, completion:{
        alert.view.superview?.userInteractionEnabled = true
        alert.view.superview?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.alertControllerBackgroundTapped)))
    })
}

func alertControllerBackgroundTapped()
{
    self.dismissViewControllerAnimated(true, completion: nil)
}

With swift 3:

func showAlertBtnClicked(sender: UIButton) {
    let alert = UIAlertController(title: "This is title", message: "This is message", preferredStyle: .alert)
    self.present(alert, animated: true) {
        alert.view.superview?.isUserInteractionEnabled = true
        alert.view.superview?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.alertControllerBackgroundTapped)))
    }
}

func alertControllerBackgroundTapped()
{
    self.dismiss(animated: true, completion: nil)
}

Solution 3 - Ios

##Swift, Xcode 9

Dismiss AlertController with cancel button

provide action to your alertController where UIAlertAction's style is .cancel

let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)

> Using this method alertController will be dismissed when user will tap to cancel action button as well as outside of the alertController.

if you don't want user to dismiss alertController after touch up outside of alertController, disable user interaction of first subviews of alertController in completion closure of present method.

self.present(alertController, animated: true) {
     alertController.view.superview?.subviews[0].isUserInteractionEnabled = false
    }

###Dismiss AlertController on touchup outside of Controller view If you don't want cancel button in your controller view and want to dismiss controller when user touchup outside of controller view, do so

self.present(alertController, animated: true) {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissAlertController))
        alertController.view.superview?.subviews[0].addGestureRecognizer(tapGesture)
}

@objc func dismissAlertController(){
    self.dismiss(animated: true, completion: nil)
}

Solution 4 - Ios

If you are using Swift :

Add an action with addAction(_:) and style:UIAlertActionStyle.Cancel.

The `handler will be called when ou tap on the button or outside the frame.

var alertVC = UIAlertController(...) // initialize your Alert View Controller
        
        alertVC.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: {
            (alertAction: UIAlertAction!) in
            alertVC.dismissViewControllerAnimated(true, completion: nil)
        }))

Objective-C :

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:...];


[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
   [alertVC dismissViewControllerAnimated:YES completion:nil];
}]];

Solution 5 - Ios

Swift 4:

Dismiss Action Sheet when User Taps outside Action Sheet created using UIAlertController

Code Snippet:

// Declare Action Sheet reference
var actionSheet: UIAlertController!

// Init and Show Action Sheet
func showActionSheetClicked(sender: UIButton) {
    
    // Init Action Sheet
    actionSheet = UIAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
        
    self.present(actionSheet, animated: true) {
        // Enabling Interaction for Transperent Full Screen Overlay
        self.actionSheet.view.superview?.subviews.first?.isUserInteractionEnabled = true
        
        // Adding Tap Gesture to Overlay
        self.actionSheet.view.superview?.subviews.first?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.actionSheetBackgroundTapped)))
    }
}

// To dismiss Action Sheet on Tap
@objc func actionSheetBackgroundTapped() {
    self.actionSheet.dismiss(animated: true, completion: nil)
}

Solution 6 - Ios

The easiest way in Obj-C:

UIAlertController *alert = [UIAlertController alertControllerWithTitle: ...
[self presentViewController:alert animated:YES completion:^{
                                       [alert.view.superview addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(alertControllerBackgroundTapped)]];
                                   }];

and then:

- (void)alertControllerBackgroundTapped
{
    [self dismissViewControllerAnimated: YES
                             completion: nil];
}

Solution 7 - Ios

- (void)addBackgroundDismissTapForAlert:(UIAlertController *)alert {
    if (!alert.view.superview) {
        return;
    }
    alert.view.superview.userInteractionEnabled = YES;
    [alert.view.superview addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(alertControllerBackgroundTapped)]];
    for (UIView *subV in alert.view.superview.subviews) {
        if (subV.width && subV.height) {
            subV.userInteractionEnabled = YES;
            [subV addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(alertControllerBackgroundTapped)]];
        }
    }
}
- (void)alertControllerBackgroundTapped {

    [self dismissViewControllerAnimated: YES
                         completion: nil];
}

Solution 8 - Ios

    UIView *alertView = self.alertController.view;
UIView *superPuperView = self.alertController.view.superview;
CGPoint tapCoord = [tap locationInView:superPuperView];
if (!CGRectContainsPoint(alertView.frame, tapCoord)) {
    //dismiss alert view
}

Solution 9 - Ios

If you view debug the superview of the alert, you see its not as simple as adding a tap gesture recognizer to the UITransitionView of the _UIAlertControllerView.You can do this instead

[presenter presentViewController:alertController animated:YES completion:^{
    NSArray <UIView *>* superviewSubviews = alertController.view.superview.subviews;
    for (UIView *subview in superviewSubviews) {
        if (CGRectEqualToRect(subview.bounds, weakSelf.view.bounds)) {
            [subview addSingleTapGestureWithTarget:weakSelf action:@selector(dismissModalTestViewController)];
        }
    }
}];

Solution 10 - Ios

On iOS 15 it appears the view hierarchy for UIAlertController has changed yet again. It's presented as a new UIWindow that contains the controller itself. So in order to dismiss on tap outside:

present(alertController, animated: true) { [weak self] in
    guard let self = self else { return }

    let dismissGesture = UITapGestureRecognizer(target: self, action: #selector(self.shouldDismiss))

    self.alertController.view.window?.isUserInteractionEnabled = true
    self.alertController.view.window?.addGestureRecognizer(dismissGesture)
}

and for shouldDismiss function:

@objc private func shouldDismiss() {
    alertController.dismiss(animated: true)
}

Solution 11 - Ios

The simplest way:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self button];
    
}

- (void) button {
    UIButton * AlertButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [AlertButton setTitle:@"Button" forState:UIControlStateNormal];
    AlertButton.frame = CGRectMake((self.view.frame.size.width/2) - 50 , (self.view.frame.size.height/2) - 25, 100, 50);
    [AlertButton addTarget:self action:@selector(Alert) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:AlertButton];
}

- (void)Alert {
    UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Alert Title" message:@"Alert Message" preferredStyle:UIAlertControllerStyleAlert];
    [self presentViewController: alert animated: YES completion:^{ alert.view.superview.userInteractionEnabled = YES; [alert.view.superview addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(DismissAlertByTab)]]; }];
}

- (void)DismissAlertByTab
{
    [self dismissViewControllerAnimated: YES completion: nil];
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionleizh00701View Question on Stackoverflow
Solution 1 - IosVivek YadavView Answer on Stackoverflow
Solution 2 - IoschancyWuView Answer on Stackoverflow
Solution 3 - IosKazi Abdullah Al MamunView Answer on Stackoverflow
Solution 4 - IosKevin MachadoView Answer on Stackoverflow
Solution 5 - IosMuthukumar ChinnuView Answer on Stackoverflow
Solution 6 - IososkarkoView Answer on Stackoverflow
Solution 7 - Iossongxing10000View Answer on Stackoverflow
Solution 8 - IosSlashikView Answer on Stackoverflow
Solution 9 - IosMichael LorenzoView Answer on Stackoverflow
Solution 10 - IosgeoffView Answer on Stackoverflow
Solution 11 - IosIbrahimView Answer on Stackoverflow