UIAlertController的使用
UIAlertController 繼承自 UIViewController ,用以向用戶顯示提醒信息。自iOS 8開始,Apple用 UIAlertController 替換了 UIAlertView 和 UIAlertSheet 。
警報控制器( UIAlertController )有 警告框 ( Alert View )和 操作表 ( Action Sheet )兩種形式。 Alert View 和 Action Sheet 雖然呈現樣式不同,但創建步驟一樣。步驟如下:
- 創建 UIAlertContorller
- 向警報控制器添加按鈕
- 顯示 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 類只能原樣使用,不支持子類化。此類的視圖層次結構是私有的,不能修改。
參考資料:
來自:http://www.jianshu.com/p/a5307dd8c424