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或其他常規寬度的設備上拉菜單

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