如何在 UIAlertController 外部点击时关闭 UIAlertController?

How to dismiss UIAlertController when tap outside the UIAlertController?

如何在点击 UIAlertController 外部时关闭 UIAlertController

我可以添加 UIAlertAction 样式 UIAlertActionStyleCancel 来关闭 UIAlertController

但我想添加这样的功能,当用户在 UIAlertController 之外点击时,UIAlertController 将消失。怎么做?谢谢。

添加样式为 UIAlertActionStyleCancel 的单独取消操作。这样当用户在外面点击时,你会得到回调。

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

如果您正在使用 Swift :

使用 addAction(_:)style:UIAlertActionStyle.Cancel 添加操作。

当您点击按钮或框架外时,将调用`处理程序。

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];
}]];

如果您的目标设备具有 iOS > 9.3 并使用 Swift 并且 preferredStyle 是 A​​lert 您可以使用如下代码段:

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

与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)
}
    UIView *alertView = self.alertController.view;
UIView *superPuperView = self.alertController.view.superview;
CGPoint tapCoord = [tap locationInView:superPuperView];
if (!CGRectContainsPoint(alertView.frame, tapCoord)) {
    //dismiss alert view
}

最简单的方法:

- (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];
}

Obj-C 中最简单的方法:

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

然后:

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

如果您查看调试警报的超级视图,您会发现它不像向 _UIAlertControllerView.You 的 UITransitionView 添加点击手势识别器那么简单,可以改为执行此操作

[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)];
        }
    }
}];
- (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];
}

Swift, Xcode 9

使用取消按钮关闭 AlertController

向您的 alertController 提供操作,其中 UIAlertAction 的样式是 .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.

如果您不希望用户在调整 alertController 外部后关闭 alertController,请在当前方法完成关闭时禁用 alertController 的第一个子视图的用户交互。

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

在 Controller 视图之外进行修饰时关闭 AlertController

如果您不想在控制器视图中使用取消按钮,并且想在控制器视图之外的用户触摸时关闭控制器,请这样做

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

Swift 4:

当用户在使用 UIAlertController

创建的操作 Sheet 外部点击时关闭操作 Sheet

代码片段:

// 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)
}

在 iOS 15 上,UIAlertController 的视图层次结构似乎又发生了变化。它显示为包含控制器本身的新 UIWindow。所以为了在外面关闭点击:

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

shouldDismiss 函数:

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