UIAlertController【对话框】

UIAlertController

在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一种模块化替换的方式来代替这两个类的功能和作用。

最基础的对话框

创建对话框视图控制器

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:<#(NSString *)#> message:<#(NSString *)#> preferredStyle:<#(UIAlertControllerStyle)#>]
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"这个是UIAlertController的标准样式" preferredStyle:UIAlertControllerStyleAlert];

要特别注意第三个参数,确定选择的是对话框样式(alert)还是上拉菜单样式(action sheet)。
UIAlertControllerStyle有两个枚举常量:

  • UIAlertControllerStyleActionSheet (上拉菜单样式)
  • UIAlertControllerStyleAlert (对话框样式)

显示对话框视图控制器

[self presentViewController:alertController animated:YES completion:nil];

效果演示

这里写图片描述


动作按钮添加到控制器

[UIAlertAction actionWithTitle:<#(NSString *)#> style:<#(UIAlertActionStyle)#> handler:<#^(UIAlertAction * _Nonnull action)handler#>]

可以将动作按钮添加到控制器上。UIAlertAction由【标题字符串】、【样式】以及 【 当用户选中该动作时运行的代码块 】组成。通过UIAlertActionStyle,可以选择如下三种动作样式:【常规(default)】、【取消(cancel)】以及【警示(destruective)】。为了实现原来我们在创建UIAlertView时创建的按钮效果,我们只需创建动作按钮并将它们添加到控制器上即可。

UIAlertAction *cancerAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancerAction];
[alertController addAction:okAction];
  • 按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
    Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’
  • “警示”样式: 按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。

效果演示

这里写图片描述


添加文本对话框

UIAlertController非常灵活性,可以向对话框中添加任意数目的UITextField对象,并且可以使用所有的UITextField特性。当向对话框控制器中添加文本框时,需要指定一个用来配置文本框的代码块。

举个例子,要建立包含账号和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,将密码输入框设置使用安全文本输入,在“登陆”按钮按下时,我们让程序读取文本框中的值,并输出。

#import "ViewController.h"

@interface ViewController ()

@property(strong,nonatomic) UIButton *button;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.button = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [[UIScreen mainScreen] bounds].size.width, 20)];
    [self.button setTitle:@"跳转" forState:UIControlStateNormal];
    [self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [self.view addSubview:self.button];

    [self.button addTarget:self action:@selector(clickMe:) forControlEvents:UIControlEventTouchUpInside];

}

-(void)clickMe:(id)sender{

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"文本对话框" message:@"包含账号和密码对话框示例" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"账号";
    }];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"密码";
        textField.secureTextEntry = YES;
    }];

    // 控制器上添加登陆按钮,在“登陆”按钮按下时,我们让程序读取文本框中的值,并输出
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"登陆" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        UITextField *login = alertController.textFields.firstObject;
        UITextField *password = alertController.textFields.lastObject;
        NSLog(@"用户名 = %@,密码 = %@",login.text, password.text);
    }];
    [alertController addAction:okAction];

    // 控制器上添加取消按钮
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
    [alertController addAction:cancelAction];

    [self presentViewController:alertController animated:YES completion:nil];   
}
@end

效果展示

这里写图片描述


完善文本对话框

要实现让”账号”文本框中至少有3个字符才能激活“登陆”按钮。

  • 在UIAlertController中并没有相应的方法,因此我们需要向“账号”文本框中添加一个Observer。Observer模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。我们可以在构造代码块中添加如下的代码片段来实现。
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
    textField.placeholder = @"账号";
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification object:textField];
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
    textField.placeholder = @"密码";
    textField.secureTextEntry = YES;
}];
  • 当视图控制器释放的时候我们需要移除这个Observer,我们通过在每个按钮动作的handler代码块(还有其他任何可能释放视图控制器的地方)中添加合适的代码来实现它。比如说在okAction这个按钮动作中:
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"登陆" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    UITextField *login = alertController.textFields.firstObject;
    UITextField *password = alertController.textFields.lastObject;
    NSLog(@"用户名 = %@,密码 = %@",login.text, password.text);
    // 视图控制器释放的时候我们需要移除这个Observer
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
}];
  • 在显示对话框之前,我们要冻结“登陆”按钮
okAction.enabled = NO;
  • 在激活按钮状态前检查“登录”文本框的内容
- (void)alertTextFieldDidChange:(NSNotification *)notification{
    UIAlertController *alertController = (UIAlertController *)self.presentedViewController;
    if (alertController){
        UITextField *login = alertController.textFields.firstObject;
        UIAlertAction *loginAction = alertController.actions.lastObject;
        loginAction.enabled = login.text.length > 2;
    }
}

完整代码

#import "ViewController.h"
@interface ViewController ()
@property(strong,nonatomic) UIButton *button;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    self.button = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, [[UIScreen mainScreen] bounds].size.width, 20)];
    [self.button setTitle:@"跳转" forState:UIControlStateNormal];
    [self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [self.view addSubview:self.button];

    [self.button addTarget:self action:@selector(clickMe:) forControlEvents:UIControlEventTouchUpInside];

}

-(void)clickMe:(id)sender{

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"文本对话框" message:@"包含账号和密码对话框示例" preferredStyle:UIAlertControllerStyleAlert];

    // 1.创建账号文本框,向登录文本框中添加一个Observer
    [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
        textField.placeholder = @"账号";
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification object:textField];
    }];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
        textField.placeholder = @"密码";
        textField.secureTextEntry = YES;
    }];

    // 2.创建取消按钮
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
    }];

    // 3.创建登陆按钮,在“登陆”按钮按下时,我们让程序读取文本框中的值,并输出
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"登陆" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        UITextField *login = alertController.textFields.firstObject;
        UITextField *password = alertController.textFields.lastObject;
        NSLog(@"用户名 = %@,密码 = %@",login.text, password.text);
        // 视图控制器释放的时候我们需要移除这个Observer
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
    }];

    // 4.冻结“登陆”按钮
    okAction.enabled = NO;

    // 5.添加取消按钮和登陆按钮
    [alertController addAction:cancelAction];
    [alertController addAction:okAction];

    [self presentViewController:alertController animated:YES completion:nil];
}

// 在激活按钮状态前检查“登录”文本框的内容
- (void)alertTextFieldDidChange:(NSNotification *)notification{
    UIAlertController *alertController = (UIAlertController *)self.presentedViewController;
    if (alertController){
        UITextField *login = alertController.textFields.firstObject;
        UIAlertAction *loginAction = alertController.actions.lastObject;
        loginAction.enabled = login.text.length > 2;
    }
}
@end

效果展示

这里写图片描述 这里写图片描述


上拉菜单

当需要给用户展示一系列选择的时候,上拉菜单就能够派上大用场了。和对话框不同,上拉菜单的展示形式和设备大小有关。在iPhone上(紧缩宽度),上拉菜单从屏幕底部升起。在iPad上(常规宽度),上拉菜单以弹出框的形式展现。

创建上拉菜单的方式和创建对话框的方式非常类似,唯一的区别是它们的形式。

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"保存或删除数据" message:@"删除数据将不可恢复" preferredStyle:UIAlertControllerStyleActionSheet];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"删除" style:UIAlertActionStyleDestructive handler:nil];
UIAlertAction *archiveAction = [UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault handler:nil];

[alertController addAction:cancelAction];
[alertController addAction:deleteAction];
[alertController addAction:archiveAction];

[self presentViewController:alertController animated:YES completion:nil];

效果展示

这里写图片描述
- 不能在上拉菜单中添加文本框,如果您强行作死添加了文本框,那么就会荣幸地得到一个运行时异常:Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert
- 如果上拉菜单中有“取消”按钮的话,那么它永远都会出现在菜单的底部,不管添加的次序是如何(就是这么任性)。其他的按钮将会按照添加的次序从上往下依次显示。《iOS 用户界面指南》要求所有的“毁坏”样式按钮都必须排名第一


iPad或其他常规宽度的设备上拉菜单

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章