UIAlertController 如何处理在 IPad 上点击外部时的 dismiss?

28

iOS8之前,我们使用UIActionSheet来显示警报,现在我们需要使用UIAlertController。

在使用UIActionSheet时,我们可以通过将clickedButtonAtIndex与cancelButtonIndex进行比较来轻松处理用户点击弹出框外部(这意味着他想取消操作)的情况-如果用户确实按下了弹出窗口外部,我们会在此函数中得到取消按钮索引。

如何处理新的UIAlertController中这些情况?我尝试使用“ completion”块,但它没有任何上下文。有没有一种简单的方法来处理这个问题?(除了在某些常规变量中“保存”操作状态)。

3个回答

45

您可以使用样式为UIAlertActionStyleCancel的操作,并且当用户在弹出窗口外部点击时,将调用此操作的处理程序。

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

请注意,使用弹出视图时UIAlertController将删除取消按钮,即使您将其添加为操作。用户通过触摸弹出视图外部来取消弹出视图,因此不需要取消按钮。 - Reefwing
1
注意:仅在使用UIAlertControllerStyleActionSheet AlertController样式时,具有UIAlertActionStyleCancel样式的操作才会关闭AlertController。它不适用于UIAlertControllerStyleAlert。 - micnguyen
@JDG 是的,但是警报样式无论如何都不能通过外部点击取消,所以这并不重要。 - Supertecnoboff
这与 OP 的问题不同,但是您可以使用类似于 SDCAlertView Cocoapod 的东西,它可以选择性地允许外部轻触来解除。 - Chris Prince
请注意,即使在iPad上,取消操作不会显示在控制器中,但其完成处理程序仍将被调用。 - Jason McClinsey
显示剩余2条评论

16

适用于UIAlertController的解决方案,只需将手势识别器添加到UIAlertController的父视图中即可。

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

1

UITapGestureRecognizer 对我没起作用,所以我使用了这种方法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接