【问题标题】:How to dismiss UIAlertController when tap outside the UIAlertController?在 UIAlertController 外部点击时如何关闭 UIAlertController?
【发布时间】:2015-07-16 12:52:31
【问题描述】:

UIAlertController之外点击时如何关闭UIAlertController

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

但我想添加当用户在UIAlertController 之外点击时UIAlertController 将关闭的功能。怎么做?谢谢。

【问题讨论】:

标签: ios uialertview uialertcontroller


【解决方案1】:

添加一个单独的取消操作,样式为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
}))

【讨论】:

  • 这不是警报对话框的标准行为,因为它们被设计为始终是模态的。
  • 在 iPhone 上显示 UIAlertActionStyleCancel (并且点击不起作用),在 iPad 上被隐藏,因为它被替换为点击视图。
  • 您的 Swift 5.0 版本只是添加了一个“取消”按钮,您可以为其分配代码,但在警报之外点击不会触发任何内容,您必须单击该按钮。
  • 和我一样。上面的实现不会使对话框在触摸时关闭
【解决方案2】:

如果您使用的是 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];
}]];

【讨论】:

  • 效果不错,但是否可以不显示“关闭”按钮?
  • @bashan 是的,您必须选择正确的UIAlertActionStyle。在此示例中,我将按钮设置为 Cancel 样式。您可以将其设置为Default
  • 将按钮更改为默认将禁用在点击菜单外部时关闭菜单的功能。
  • 有没有办法在菜单外按下来关闭它,但没有“取消”按钮?
【解决方案3】:

如果您的目标设备是 iOS > 9.3 并且使用 Swift 并且首选样式为 Alert,您可以使用 sn-p,如下所示:

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

【讨论】:

  • 从 iOS 9.3 开始,您必须将手势识别器添加到超级视图 (alert.view.superview.subviews[1]) 的第二个子视图,而不是超级视图本身。如文档中所述,UIAlertController 的视图层次结构是私有的,因此无法保证它在未来的 iOS 版本中不会改变。
  • 我已将您的答案与 sfongxing10000 的答案混合在一起,并想出将轻击手势添加到 alert.view.superview 及其所有 subviews。它现在正在运行,iOS 11.2!
  • 不确定这是否是 Swift 5 中的更改,但您必须将 @objc 添加到 alertControllerBackgroundTapped 函数中,否则 Xcode 会解释。除此之外,Swift 3 版本也适用于 Swift 5,谢谢。
【解决方案4】:
    UIView *alertView = self.alertController.view;
UIView *superPuperView = self.alertController.view.superview;
CGPoint tapCoord = [tap locationInView:superPuperView];
if (!CGRectContainsPoint(alertView.frame, tapCoord)) {
    //dismiss alert view
}

【讨论】:

    【解决方案5】:

    最简单的方法:

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        如果您查看调试警报的超级视图,您会发现它不像向 _UIAlertControllerView 的 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)];
                }
            }
        }];
        

        【讨论】:

          【解决方案8】:
          - (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];
          }
          

          【讨论】:

          • 这确实有效,从 iOS 11.2 开始!我也必须向所有子视图添加相同的点击手势。
          【解决方案9】:

          斯威夫特,Xcode 9

          使用取消按钮关闭 AlertController

          UIAlertAction 的样式为.cancel 的 alertController 提供操作

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

          当用户点击取消操作按钮以及在 alertController 之外使用此方法时,alertController 将被关闭。

          如果您不希望用户在alertController 之外进行修改后关闭alertController,请在当前方法的完成关闭中禁用alertController 的第一个子视图的用户交互。

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

          在 Controller 视图之外的 touchup 上关闭 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)
          }
          

          【讨论】:

          • 谢谢...您节省了我的时间。
          • 这么简单...谢谢!
          • “使用此方法,当用户点击取消操作按钮以及在 alertController 之外,alertController 将被关闭。”我不相信这是真的,当您点击外部警报控制器警报时,它不会让第一响应者辞职。只有在使用操作表时在 alertController 之外点击时,它才会退出第一响应者。
          【解决方案10】:

          斯威夫特 4:

          当用户在使用 UIAlertController 创建的操作表之外点击时关闭操作表

          代码片段:

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

          【讨论】:

          • 是的,它在完成添加手势识别器时有效。谢谢!
          猜你喜欢
          • 1970-01-01
          • 2014-10-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多