UIAlertController的使用

StuBergmann 7年前發布 | 12K 次閱讀 iOS開發 移動開發 UIAlertController

UIAlertController 繼承自 UIViewController ,用以向用戶顯示提醒信息。自iOS 8開始,Apple用 UIAlertController 替換了 UIAlertView 和 UIAlertSheet 。

警報控制器( UIAlertController )有 警告框 ( Alert View )和 操作表 ( Action Sheet )兩種形式。 Alert View 和 Action Sheet 雖然呈現樣式不同,但創建步驟一樣。步驟如下:

  1. 創建 UIAlertContorller
  2. 向警報控制器添加按鈕
  3. 顯示 UIAlertContorller

下面通過創建一個demo來學習一下。

打開Xcode,創建新的工程。選擇 iOS 一欄下的 Application 中的 Single View Application 模板,點擊 Next 。在 Product Name 中填寫 AlertController ,點擊 Next ,選擇文件存放位置,點擊 Create 創建工程。

打開剛創建工程的 storyboard ,在 storyboard 中自上而下依次添加以下控件,內容為 UIAlertControllerStyleAlert 的 UILabel ,標題為 Show Alert 的 UIButton ,標題為 Login Alert 的 UIButton ,內容為 UIAlertControllerStyleActionSheet 的 UILabel ,標題為 Action Sheet 的 UIButton 。如下圖:

AlertControllerStoryboard.png

把 UIButton 拖拽到 ViewController.m 的接口部分,類型為 IBAction 。完成后代碼如下:

#import "ViewController.h"

@interface ViewController ()

- (IBAction)showAlertView:(UIButton *)sender;
- (IBAction)showLoginAlertView:(UIButton *)sender;
- (IBAction)showActionSheet:(UIButton *)sender;

@end

簡單對話框樣式

1.創建警報控制器

創建 UIAlertContorller 非常簡單,不需要設置代理、不需要指定按鈕。下面先在 showAlertView: 方法中,創建 UIAlertContorller 。

- (IBAction)showAlertView:(UIButton *)sender
{
    // 1.創建UIAlertController
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert Title"
                                                                             message:@"The message is ..."
                                                                      preferredStyle:UIAlertControllerStyleAlert];
}

這里的 preferredStyle: 參數有 UIAlertControllerStyleAlert 和 UIAlertControllerStyleActionSheet 兩種,這里我們要創建的是 Alert View 所以使用第一種。

2.添加按鈕

使用 actionWithTitle: style: handler: 方法創建 UIAlertAction 對象,之后把對象添加到警報控制器。

UIAlertAction 對象由標題、樣式和用戶單擊該按鈕時運行的代碼塊三部分組成。 UIAlertActionStyle 有三種樣式,樣式一 UIAlertActionStyleCancel ,用于取消操作、不作任何修改,就是常見的 取消 按鈕;樣式二 UIAlertActionStyleDefault ,按鈕的默認樣式;第三種是 UIAlertActionStyleDestructive ,用于對數據進行更改或刪除的操作,這種樣式的按鈕標題會自動使用紅色顯示。

在 showAlertView: 方法中添加 Cancel 按鈕和 OK 按鈕。

- (IBAction)showAlertView:(UIButton *)sender
{
    ...
    // 2.創建并添加按鈕
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"OK Action");
    }];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"Cancel Action");
    }];

    [alertController addAction:okAction];           // A
    [alertController addAction:cancelAction];       // B
}

3.顯示 UIAlertContorller

顯示 UIAlertContorller 。

- (IBAction)showAlertView:(UIButton *)sender
{
    ...
    // 3.呈現UIAlertContorller
    [self presentViewController:alertController animated:YES completion:nil];
}

在視圖控制器中顯示如下:

AlertView

改變上面 addAction: 方法順序,運行app,你會發現 Alert View 中按鈕順序不變。當 Alert View 樣式中有 Cancel 按鈕時, Cancel 按鈕總是顯示在左側,與添加按鈕的順序無關。

在 showAlertView: 方法中再添加一個 UIAlertActionStyleDestructive 樣式的 Reset 按鈕。

- (IBAction)showAlertView:(UIButton *)sender
{
    ...
    UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"Reset Action");
    }];
    [alertController addAction:resetAction];        // C
    [alertController addAction:okAction];           // A
    [alertController addAction:cancelAction];       // B
    ...
}

在視圖控制器中顯示如下:

當 Alert View 中存在一個或兩個按鈕時,按鈕會水平排布;按鈕大于兩個時會像 Action Sheet 那樣豎列展示。把上面 addAction: 順序改變為B、A、C,運行app,視圖控制器顯示如下:

可以看到上面只要有 UIAlertActionStyleCancel 樣式的按鈕,該按鈕總是在最底部,其他按鈕順序由添加順序決定。如果包含 UIAlertActionStyleDestructive 樣式的按鈕,一般先添加,以便在第一個位置顯示。每一個警報控制器只能包含一個 Cancel 按鈕,如果你添加了兩個或多個,在運行時會拋出 NSInternalInconsistencyException 的異常。

登錄文本框

UIAlerController 的另一個用途是我們可以向警報控制器中添加任意數量的 UITextField 作為警報控制器內容視圖中的一部分。比如常見的登陸框。

為了創建一個上圖中的登錄框,我們需要為警報控制器添加兩個文本框。每一個文本框添加合適的占位符以提示需要輸入文本信息,并為需要輸入密碼的文本框啟用安全文本,以確保密碼安全。更新后的 showLoginAlertView: 代碼如下:

- (IBAction)showLoginAlertView:(UIButton *)sender
{
    // 1.創建UIAlertController
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Login"
                                                                             message:@"Enter Your Account Info Below"
                                                                      preferredStyle:UIAlertControllerStyleAlert];

    // 2.1 添加文本框
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"username";
    }];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"password";
        textField.secureTextEntry = YES;
    }];
}

繼續在 showLoginAlertView: 方法中添加 Cancel 按鈕和 Login 按鈕,在點擊 Login 按鈕時獲取文本框中的賬號和密碼并輸出到控制臺。

- (IBAction)showLoginAlertView:(UIButton *)sender
{
    ...
    // 2.2  創建Cancel Login按鈕
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"Cancel Action");
    }];
    UIAlertAction *loginAction = [UIAlertAction actionWithTitle:@"Login" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        UITextField *userName = alertController.textFields.firstObject;
        UITextField *password = alertController.textFields.lastObject;

        // 輸出用戶名 密碼到控制臺
        NSLog(@"username is %@, password is %@",userName.text,password.text);
    }];
}

上面的代碼中,警報控制器中的 UITextField 的順序由添加順序決定。

最后添加按鈕,顯示警報控制器。

- (IBAction)showLoginAlertView:(UIButton *)sender
{
    ...
    // 2.3 添加按鈕
    [alertController addAction:cancelAction];
    [alertController addAction:loginAction];

    // 3.顯示警報控制器
    [self presentViewController:alertController animated:YES completion:nil];
}

現在運行app,在第一個文本框中輸入 pro648 ,在第二個文本框內輸入 x ,點擊 Login 按鈕,控制臺輸出如下:

username is pro648, password is x

在實際應用中我們一般會對用戶名和密碼長度進行限制,當長度不足時應該禁用 Login 按鈕。我們可以通過為文本框添加一個 UIControllEventEditingChanged 響應事件來實現。記得在添加按鈕前先禁用按鈕。更新后代碼如下:

- (IBAction)showLoginAlertView:(UIButton *)sender
{
    ...
    // 2.1 添加文本框
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"username";

        [textField addTarget:self action:@selector(alertUserAccountInfDidChange:) forControlEvents:UIControlEventEditingChanged];     // 添加響應事件
    }];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"password";
        textField.secureTextEntry = YES;

        [textField addTarget:self action:@selector(alertUserAccountInfDidChange:) forControlEvents:UIControlEventEditingChanged];     // 添加響應事件
    }];

    ...
    // 2.3 添加按鈕
    loginAction.enabled = NO;   // 禁用Login按鈕
    [alertController addAction:cancelAction];
    [alertController addAction:loginAction];
    ...
}

- (void)alertUserAccountInfDidChange:(UITextField *)sender
{
    UIAlertController *alertController = (UIAlertController *)self.presentedViewController;

    if (alertController)
    {
        UITextField *userName = alertController.textFields.firstObject;
        UIAlertAction *loginAction = alertController.actions.lastObject;
        UITextField *password = alertController.textFields.lastObject;
        if (userName.text.length>3 && password.text.length > 6)     // 用戶名必須大于三位 密碼必須大于六位
        {
            loginAction.enabled = YES;
        }
    }
}

UIAlertController 中的 textFields 和 actions 均是數組類型,第一個添加的對象index為 0 。之后按照添加的順序index依次加1,雖然前面說到 Cancel 按鈕一般顯示在左側(橫排)或底部(豎排),但并不代表它在數組中的位置是第一個或最后一個,其index是由添加的順序決定。你可以根據 username 字符串長度來禁用 Login 按鈕進行測試。

現在只有在用戶名大于三位、密碼大于六位時, Login 按鈕才可以點擊。

Action Sheet

操作表一般用于為用戶提供一組可供選擇的操作選項,如刪除,恢復等。一般根據設備尺寸大小決定呈現形式,在iPhone上,操作表由底部滑出,在iPad上,操作表以彈出框形式出現。

創建操作表的方法與警告框類似,唯一不同在于 preferredStyle: 參數的選擇。在 showActionSheet: 方法中創建操作表。

- (IBAction)showActionSheet:(UIButton *)sender
{
    // 1.創建UIAlertController
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Action Sheet"
                                                                             message:@"Deleted data can't be restored"
                                                                      preferredStyle:UIAlertControllerStyleActionSheet];
}

下面創建并添加按鈕,最后呈現警報控制器。

- (IBAction)showActionSheet:(UIButton *)sender
{
    ...
    // 2.1 創建按鈕
    UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"Delete Action");
    }];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"Cancel Action");
    }];

    // 2.2 添加按鈕
    [alertController addAction:deleteAction];
    [alertController addAction:cancelAction];

    // 3.顯示警報控制器
    [self presentViewController:alertController animated:YES completion:nil];
}

運行app,操作表展示如下:

如果 Action Sheet 中有取消按鈕,取消按鈕每次都會在底部顯示,其他按鈕會按照添加的順序顯示。在 Action Sheet 內不能添加文本框。如果你添加了文本框,在運行時會拋出下面的異常提醒:

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert'

如上面說到的在iPad中, Action Sheet 以彈出框的形式呈現。彈出框總是需要一個錨點,錨點可以是源視圖,也可以是按鈕。在這個demo中,我們用按鈕觸發彈出框,所以這里將把按鈕作為錨點。 showActionSheet: 方法更新后如下:

- (IBAction)showActionSheet:(UIButton *)sender
{
    ...
    UIPopoverPresentationController *popover = alertController.popoverPresentationController;
    if (popover)
    {
        popover.sourceView = sender;
        popover.sourceRect = sender.bounds;
        popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
    }

    // 3.顯示警報控制器
    [self presentViewController:alertController animated:YES completion:nil];
}

如果在iPad中沒有添加上面方法,運行時會出現下面崩潰提示:

* Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0x7f88c85221f0>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

現在, Action Sheet 以觸發它的按鈕為錨點,以彈出框形式展現。

當 Action Sheet 以彈出框形式展現時, UIAlertController 會自動取消 Cancel 按鈕,用戶可以通過點擊彈出框以外的區域來取消彈出框。

退出警報控制器

警報控制器會在用戶點擊按鈕后自動消失,如果需要,也可以在代碼中實現手動退出。一般在app進入后臺時警告框和選擇表并沒有退出,我們可以通過在 viewDidLoad 方法中添加 通知中心 ,當觀察者接收到app進入后臺時,退出警報控制器。

- (void)viewDidLoad
{
    [super viewDidLoad];

    // app 進入后臺后隱藏警報控制器
    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
        [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
    }];
}

- (void)dealloc
{
    // 移除觀察者
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}

最后一定記得移除觀察者,否則會引起崩潰。

總結

下面總結下 Alert View 和 Action Sheet 的異同。

警告框 Alert View

  • 一般顯示在當前視圖控制器的中心,點擊警告框以外區域不能隱藏警告控制器。
  • 可以添加任意數量文本框。
  • 有一個或兩個按鈕時,橫向排布,如果有 Cancel 按鈕,則 Cancel 按鈕顯示在左側;有兩個以上按鈕時,豎列排布,如果有 Cancel 按鈕,則 Cancel 按鈕顯示在最底部。其他按鈕按照添加順序排布。

操作表 Action Sheet

  • 在iPhone中一般以滑出的形式顯示在當前控制器的底部,點擊警告框以外區域可以隱藏警告控制器。
  • 在iPad中以popover方式、以源視圖為錨點顯示,點擊選擇表以外的區域可以隱藏警告控制器。
  • 不能添加文本框。
  • 按鈕豎列排布,在iPhone中, Cancel 按鈕默認在底部顯示;在iPad中, Cancel 按鈕默認不顯示。

Alert View 和 Action Sheet 都只能包含一個 UIAlertActionStyleCancel 樣式的按鈕,否則運行時會崩潰。 UIAlertController 類只能原樣使用,不支持子類化。此類的視圖層次結構是私有的,不能修改。

 

參考資料:

  1. UIAlertController Changes in iOS 8
  2. UIAlertController

 

來自:http://www.jianshu.com/p/a5307dd8c424

 

 本文由用戶 StuBergmann 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!