0%

UIAlertController

UIAlertController

UIAlertController 同时替代了 UIAlertView 和 UIActionSheet,从系统层级上统一了 alert 的概念 —— 即以 modal 方式或 popover 方式展示。

UIAlertController 是 UIViewController 的子类,而非其先前的方式。因此新的 alert 可以由 view controller 展示相关的配置中获益很多。

UIAlertController 不管是要用 alert 还是 action sheet 方式展示,都要以 title 和 message 参数来初始化。Alert 会在当前显示的 view controller 中心以模态形式出现,action sheet 则会在底部滑出。Alert 可以同时有按钮和输入框,action sheet 仅支持按钮。

新的方式并没有把所有的 alert 按钮配置都放在初始化函数中,而是引入了一个新类 UIAlertAction 的对象,在初始化之后可以进行配置。这种形式的 API 重构让对按钮数量、类型、顺序方便有了更大的控制。同时也弃用了 UIAlertView 和 UIActionSheet 使用的 delegate 这种方式,而是采用更简便的完成时回调。
- 摘自 Mattt Thompson

UIAlertControllerStyle ——Alert 样式

typedef enum UIAlertControllerStyle : NSInteger {
    UIAlertControllerStyleActionSheet = 0, // 从底部向上推出的 action sheet 列表方式
    UIAlertControllerStyleAlert            // 模态显示的 alert
} UIAlertControllerStyle;

UIAlertActionStyle —— 按钮样式

typedef enum UIAlertActionStyle : NSInteger {
    UIAlertActionStyleDefault = 0,
    UIAlertActionStyleCancel,
    UIAlertActionStyleDestructive
} UIAlertActionStyle;
  1. UIAlertActionStyleDefault
    默认风格样式的动作按钮;
  2. UIAlertActionStyleCancel
    取消操作并且保持视图内容不变的动作按钮;
  3. UIAlertActionStyleDestructive
    可能更改或删除数据样式的动作按钮,警示性样式,默认按钮字体为红色,提示用户这样做可能会删除或者改变某些数据.

1.1 一个按钮的 Alert 样式

一个按钮的Alert样式

创建方法

// 1.实例化alertController
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"标题"
                                                               message:@"消息"
                                                        preferredStyle:UIAlertControllerStyleAlert];

// 2.实例化按钮
UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定"
                                                 style:UIAlertActionStyleDefault
                                               handler:^(UIAlertAction * _Nonnull action) {
                                                   // 点击按钮,调用此block
                                                   NSLog(@"Button Click");
                                               }];
[alert addAction:action];

//  3.显示alertController
[self presentViewController:alert animated:YES completion:nil];

1.2 标准的 Alert 样式

创建方法

//  1.实例化UIAlertController对象
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"标准的Alert 样式"
                                                               message:@"UIAlertControllerStyleAlert"
                                                        preferredStyle:UIAlertControllerStyleAlert];

//  2.1实例化UIAlertAction按钮:取消按钮
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
                                                       style:UIAlertActionStyleCancel
                                                     handler:^(UIAlertAction * _Nonnull action) {
                                                         // 点击取消按钮,调用此block
                                                         NSLog(@"取消按钮被按下!");
                                                     }];
[alert addAction:cancelAction];

//  2.2实例化UIAlertAction按钮:确定按钮
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"确定"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          // 点击按钮,调用此block
                                                          NSLog(@"确定按钮被按下");
                                                      }];
[alert addAction:defaultAction];

//  3.显示alertController
[self presentViewController:alert animated:YES completion:nil];

1.3 带有多个按钮的 Alert 样式

创建方法

//  1.实例化UIAlertController对象
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"多个按钮的Alert 样式"
                                                               message:@"有1个或者2个操作按钮的时候,按钮会水平排布。更多按钮的情况,就会像action sheet那样展示:"
                                                        preferredStyle:UIAlertControllerStyleAlert];

//  2.1实例化UIAlertAction按钮:确定按钮
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"确定"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          // 点击按钮,调用此block
                                                          NSLog(@"确定按钮被按下");
                                                      }];
[alert addAction:defaultAction];

//  2.2实例化UIAlertAction按钮:更多按钮
UIAlertAction *moreAction = [UIAlertAction actionWithTitle:@"更多"
                                                     style:UIAlertActionStyleDestructive
                                                   handler:^(UIAlertAction * _Nonnull action) {
                                                       // 点击按钮,调用此block
                                                       NSLog(@"更多按钮被按下");
                                                   }];
[alert addAction:moreAction];

//  2.3实例化UIAlertAction按钮:取消按钮
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
                                                       style:UIAlertActionStyleCancel
                                                     handler:^(UIAlertAction * _Nonnull action) {
                                                         // 点击取消按钮,调用此block
                                                         NSLog(@"取消按钮被按下!");
                                                     }];
[alert addAction:cancelAction];

//  3.显示alertController
[self presentViewController:alert animated:YES completion:nil];

2. 标准的 Alert Sheet 样式

创建方法

// 1.实例化UIAlertController对象
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"标准的Action Sheet样式"
                                                               message:@"UIAlertControllerStyleActionSheet"
                                                        preferredStyle:UIAlertControllerStyleActionSheet];

// 2.1实例化UIAlertAction按钮:取消按钮
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
                                                       style:UIAlertActionStyleCancel
                                                     handler:^(UIAlertAction * _Nonnull action) {
                                                         NSLog(@"取消按钮被按下!");
                                                     }];
[alert addAction:cancelAction];

// 2.2实例化UIAlertAction按钮:更多按钮
UIAlertAction *moreAction = [UIAlertAction actionWithTitle:@"更多"
                                                     style:UIAlertActionStyleDestructive
                                                   handler:^(UIAlertAction * _Nonnull action) {
                                                       NSLog(@"更多按钮被按下!");
                                                   }];
[alert addAction:moreAction];

// 2.3实例化UIAlertAction按钮:确定按钮
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确定"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          NSLog(@"确定按钮被按下");
                                                      }];
[alert addAction:confirmAction];

//  3.显示alertController
[self presentViewController:alert animated:YES completion:nil];

3. 带输入框样式

创建方法

// 1.实例化UIAlertController对象
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"标题"
                                                               message:@"信息"
                                                        preferredStyle:UIAlertControllerStyleAlert];

// 2.1添加输入文本框
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
    textField.placeholder = @"支付密码";
    textField.secureTextEntry = YES;
}];

// 2.2实例化UIAlertAction按钮:确定按钮
UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"确定"
                                                        style:UIAlertActionStyleDefault
                                                      handler:^(UIAlertAction * _Nonnull action) {
                                                          NSLog(@"确定按钮被按下");
                                                          UITextField *passwordTextField = alert.textFields.firstObject;
                                                          NSLog(@"读取输入密码:%@",passwordTextField.text);
                                }];
[alert addAction:confirmAction];

//  3.显示alertController
[self presentViewController:alert animated:YES completion:nil];

第三方框架:

ryanmaxwell/UIAlertController-Blocks

用 Blocks 方式封装的便捷扩展类,调用更简单:

// 通用创建方法
+ (nonnull instancetype)showInViewController:(nonnull UIViewController *)viewController
                                   withTitle:(nullable NSString *)title
                                     message:(nullable NSString *)message
                              preferredStyle:(UIAlertControllerStyle)preferredStyle
                           cancelButtonTitle:(nullable NSString *)cancelButtonTitle
                      destructiveButtonTitle:(nullable NSString *)destructiveButtonTitle
                           otherButtonTitles:(nullable NSArray *)otherButtonTitles
#if TARGET_OS_iOS
          popoverPresentationControllerBlock:(nullable UIAlertControllerPopoverPresentationControllerBlock)popoverPresentationControllerBlock
#endif
                                    tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock;

// 指明创建 UIAlertControllerStyleAlert 样式的弹窗:
+ (nonnull instancetype)showAlertInViewController:(nonnull UIViewController *)viewController
                                        withTitle:(nullable NSString *)title
                                          message:(nullable NSString *)message
                                cancelButtonTitle:(nullable NSString *)cancelButtonTitle
                           destructiveButtonTitle:(nullable NSString *)destructiveButtonTitle
                                otherButtonTitles:(nullable NSArray *)otherButtonTitles
                                         tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock;

// 指明创建 UIAlertControllerStyleActionSheet 样式的弹窗:
+ (nonnull instancetype)showActionSheetInViewController:(nonnull UIViewController *)viewController
                                              withTitle:(nullable NSString *)title
                                                message:(nullable NSString *)message
                                      cancelButtonTitle:(nullable NSString *)cancelButtonTitle
                                 destructiveButtonTitle:(nullable NSString *)destructiveButtonTitle
                                      otherButtonTitles:(nullable NSArray *)otherButtonTitles
#if TARGET_OS_iOS
                     popoverPresentationControllerBlock:(nullable UIAlertControllerPopoverPresentationControllerBlock)popoverPresentationControllerBlock
#endif
                                               tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock;

调用示例

示例一:
[UIAlertController showAlertInViewController:self
                                           withTitle:@"无法访问位置信息"
                                             message:@"请去设置-隐私-定位服务中开启该功能"
                                   cancelButtonTitle:@"知道了"
                              destructiveButtonTitle:nil
                                   otherButtonTitles:nil
                                            tapBlock:nil];
示例二:
self.tapBlock = ^(UIAlertController *controller, UIAlertAction *action, NSInteger buttonIndex){
            if (buttonIndex == controller.destructiveButtonIndex) {
                NSLog(@"Delete");
            } else if (buttonIndex == controller.cancelButtonIndex) {
                NSLog(@"Cancel");
            } else if (buttonIndex >= controller.firstOtherButtonIndex) {
                NSLog(@"Other %ld", (long)buttonIndex - controller.firstOtherButtonIndex + 1);
            }
        };

// Alert 样式
[UIAlertController showAlertInViewController:self
                                       withTitle:@"Test Alert"
                                         message:@"Test Message"
                               cancelButtonTitle:@"Cancel"
                          destructiveButtonTitle:@"Delete"
                               otherButtonTitles:@[@"First Other", @"Second Other"]
                                        tapBlock:self.tapBlock];
// ActionSheet 样式
[UIAlertController showActionSheetInViewController:self
                                         withTitle:@"Test Action Sheet"
                                           message:@"Test Message"
                                 cancelButtonTitle:@"Cancel"
                            destructiveButtonTitle:@"Delete"
                                 otherButtonTitles:@[@"First Other", @"Second Other"]
#if TARGET_OS_iOS
                popoverPresentationControllerBlock:^(UIPopoverPresentationController *popover){

                    popover.sourceView = self.view;
                    popover.sourceRect = sender.frame;
                }
#endif
                                          tapBlock:self.tapBlock];

Tips: 如果不需要某个按钮,就给按钮的 Title 传 nil。

  • ButtonIndex 判断:
    static NSInteger const UIAlertControllerBlocksCancelButtonIndex = 0; // 取消、返回按钮
    static NSInteger const UIAlertControllerBlocksDestructiveButtonIndex = 1; // 更改、删除按钮
    static NSInteger const UIAlertControllerBlocksFirstOtherButtonIndex = 2; // 第一个默认按钮
    button Index

第三方框架:kukumaluCN/JXTAlertManager

这个框架支持链式语法:
使用示例:

1.Alert

[self jxt_showAlertWithTitle:@"title"
                     message:@"message"
           appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
    alertMaker.
    addActionCancelTitle(@"cancel").
    addActionDestructiveTitle(@"按钮1");
} actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
    if (buttonIndex == 0) {
        NSLog(@"cancel");
    }
    else if (buttonIndex == 1) {
        NSLog(@"按钮1");
    }
}];

2.AlertSheet

[self jxt_showAlertWithTitle:@"title"
                     message:@"message"
           appearanceProcess:^(JXTAlertController * _Nonnull alertMaker) {
    alertMaker.
    addActionDestructiveTitle(@"获取输入框1").
    addActionDestructiveTitle(@"获取输入框2");

    [alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"输入框1-请输入";
    }];
    [alertMaker addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"输入框2-请输入";
    }];
} actionsBlock:^(NSInteger buttonIndex, UIAlertAction * _Nonnull action, JXTAlertController * _Nonnull alertSelf) {
    if (buttonIndex == 0) {
        UITextField *textField = alertSelf.textFields.firstObject;
        [self logMsg:textField.text];//不用担心循环引用
    }
    else if (buttonIndex == 1) {
        UITextField *textField = alertSelf.textFields.lastObject;
        [self logMsg:textField.text];
    }
}];

播放系统声音、提醒声音和振动设备

// 导入框架
#import <AudioToolbox/AudioToolbox.h>

播放系统声音

AudioServicesPlaySystemSound(1005);

播放提醒声音

AudioServicesPlayAlertSound(1006);

执行震动

AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

其它开源框架

  • dogo/SCLAlertView ⭐️3000
  • GitHub:adad184/MMPopupView ⭐️1800
  • GitHub:mtonio91/AMSmoothAlert ⭐️1300
  • GitHub:12207480/TYAlertController ⭐️1000

参考资料

  • UIAlert​Controller @Mattt Thompson 撰写、 Croath Liu 翻译-Swift
  • iOS 开发笔记:提示框(UIAlertController)学习
  • iOS 8 新特性初学:UIAlertController @关东糖
  • iOS 更加优雅便捷的 UIAlertView/UIAlertController 封装使用 @霖溦
  • 模仿支付宝支付密码输入对话框

欢迎关注我的其它发布渠道