文章更新:
3月9日:推薦一個開源框架GJAlertController
。 git
許多時候,咱們須要在應用中彈出提示框,給用戶提示信息,而後讓用戶選擇執行哪一種操做。有兩種形式,一種是彈出提示框,一種是彈出提示菜單。github
提示框:進入Apple Music,在登陸時,會彈出提示輸入AppleID帳戶和密碼的提示框。
框架
提示菜單:在Apple Music中,選擇將一首歌曲加入到播放列表時,彈出以下菜單。
atom
在iOS 9.0中,UIAlertView被棄用。固然,UIAlertViewDelegate一樣被棄用。取而代之的是,使用UIAlertController
,初始化時,將preferredStyle
設爲UIAlertControllerStyleAlert
。spa
使用代理
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, , ...
初始化UIAlertView的實例。 code
注意:參數otherButtonTitles能夠有多個NSString,有分號隔開,以nil結尾便可。 對象
這裏直接上代碼,看一下出現的效果。繼承
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Other1", nil];
效果以下:
索引
若是otherButtonTitles參數有多個NSString時,效果以下:
咱們也可使用
- (NSInteger)addButtonWithTitle:(NSString *)title
來添加UIAlertView所顯示的按鈕。
@property(nonatomic, copy) NSString *title @property(nonatomic, copy) NSString *message
能夠設置這兩個屬性改變title
和message
。
不建議添加太多的按鈕,不然會下降用戶體驗。
在初始化方法中有參數delegate
,因此,若是要響應按鈕點擊事件,須要當前ViewController遵循UIAlertViewdelegate
。
若是初始化方法中的otherButtonTitles
不爲nil,那麼必需要實現
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
buttonIndex從0開始計算。這個方法調用以後,UIAlertView會自動消失。
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
這個方法能夠用與輸入框的UIAlertView。當沒有用戶沒有輸入完成時,令這個方法返回NO,使用戶沒法點擊第一個添加的按鈕。
//alertView即將呈現給用戶時調用 - (void)willPresentAlertView:(UIAlertView *)alertView //alertView已經呈現給用戶時調用 - (void)didPresentAlertView:(UIAlertView *)alertView //用戶點擊某個按鈕後,alertView即將消失時調用 - (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex //用戶點擊某個按鈕後,alertView已經消失時調用 - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
在後兩個代理方法中,buttonIndex
的值從0開始計算。在我初始化的alertView中,cancel
對應索引0
,other1
對應索引1
,other2
對應索引2
。
咱們能夠經過alertViewStyle
屬性改變alertView的樣式。
UIAlertViewStyleDefault。彈出一個標準的alertView;
UIAlertViewStyleSecureTextInput。彈出的alertView帶有一個密碼輸入框;
UIAlertViewStylePlainTextInput。彈出的alertView帶有一個普通的文本輸入框;
UIAlertViewStyleLoginAndPasswordInput。彈出的alertView有兩個輸入框,能夠分別輸入帳號密碼。
//獲取特定按鈕的索引 @property(nonatomic) NSInteger cancelButtonIndex @property(nonatomic, readonly) NSInteger firstOtherButtonIndex //返回對應索引的UITextField - (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex //UIAlertViewStyleDefault,沒有text field。 //UIAlertViewStyleSecureTextInput,text field對應索引0。 //UIAlertViewStyleDefault,text field對應索引0。 //UIAlertViewStyleDefault,login field對應索引0,password field對應索引1。 //若是參數`textFieldIndex`超出索引範圍,則會拋出`NSRangeException`異常。 //返回指定索引的按鈕的值 - (NSString *)buttonTitleAtIndex:(NSInteger)buttonIndex //彈出alertView - (void)show
UIActionSheet和UIActionSheetDelegate在iOS 8.3中被棄用。取代它的是preferredStyle
被設爲UIAlertControllerStyleActionSheet
的UIAlertController
。
在我使用App的過程當中,兩種狀況下使用UIActionSheet。
當用戶刪除東西的時候,給出提示;
在上傳頭像時,選擇用相機拍照仍是相冊照片。
- (instancetype)initWithTitle:(NSString *)title delegate:(id<UIActionSheetDelegate>)delegate cancelButtonTitle:(NSString *)cancelButtonTitle destructiveButtonTitle:(NSString *)destructiveButtonTitle otherButtonTitles:(NSString *)otherButtonTitles , ...
UIActionSheet的初始話方法和UIAlertView的初始化方法相似。
一樣地,給出一行初始化代碼,看看效果。
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"cancel" destructiveButtonTitle:@"destructive" otherButtonTitles:@"使用相機拍照", @"選擇相冊照片", nil];
destructiveButtonTitle
和otherButtonTitles
根據狀況傳值,二選一,不然就會像上圖所顯示的那樣,看起來很醜!
UIActionSheet的代理方法定義在協議UIActionSheetDelegate
中。它的代理方法和UIAlertViewDelegate中定義的方法是極其類似的。
//添加的按鈕被點擊調用 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex //actionSheet即將出現時調用 - (void)willPresentActionSheet:(UIActionSheet *)actionSheet //actionSheet已經出現時調用 - (void)didPresentActionSheet:(UIActionSheet *)actionSheet //actionSheet即將消失時調用 - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex //actionSheet已經消失時調用 - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
對於actionSheet中按鈕的索引,是按照從0開始,從上到下依次+1。依然以我初始化的actionSheet爲例,destructive
的索引是0,使用相機拍照
的索引是1,選擇相冊照片
的索引是2,cancel
的索引是3。
//獲取特定的按鈕的索引 @property(nonatomic) NSInteger cancelButtonIndex @property(nonatomic) NSInteger destructiveButtonIndex @property(nonatomic, readonly) NSInteger firstOtherButtonIndex //返回指定索引的按鈕的值 - (NSString *)buttonTitleAtIndex:(NSInteger)buttonIndex //顯示actionSheet - (void)showInView:(UIView*)view
這兩個的類的屬性、方法、代理都極其類似。
須要注意的是,當它們都有多個按鈕時,計算按鈕索引的方法是不一樣的。
UIAlertView的取消按鈕的索引永遠是0,其餘的依次+1。
UIActionSheet的索引是全部的按鈕從上到下,從0開始,一次+1。
- (void)alertViewCancel:(UIAlertView *)alertView - (void)actionSheetCancel:(UIActionSheet *)actionSheet
這兩個代理方法在什麼狀況下會調用,我沒有搞清楚!
到了iOS 9.0以後,UIAlertView和UIActionSheet都被棄用了,取而代之的就是UIAlertController
。實際上,UIAlertController在iOS 8.0之後就可使用了。
UIAlertController是繼承自UIController的,因此,使用presentViewController:animated:completaion:
方法來顯示UIAlertController。
首先,我把上面給出的UIAlertView和UIActionSheet的初始化,使用UIAlertController來實現。
//實現和UIAlertView相同的效果 UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"title" message:@"message" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { nil; }]; UIAlertAction* firstOtherAction = [UIAlertAction actionWithTitle:@"Other1" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSLog(@"other1 clicked!"); }]; UIAlertAction* secondOtherAction = [UIAlertAction actionWithTitle:@"Other2" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSLog(@"other2 clicked!"); }]; [alert addAction:cancelAction]; [alert addAction:firstOtherAction]; [alert addAction:secondOtherAction]; [self presentViewController:alert animated:YES completion:^{ nil; }];
//實現和UIActionSheet相同的效果 UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"title" message:@"message" preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { nil; }]; UIAlertAction* destructiveAction = [UIAlertAction actionWithTitle:@"destructive" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) { NSLog(@"destructive clicked"); }]; UIAlertAction* firstAction = [UIAlertAction actionWithTitle:@"使用相機拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSLog(@"使用相機拍照"); }]; UIAlertAction* secondAction = [UIAlertAction actionWithTitle:@"使用相冊照片" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { NSLog(@"使用相冊照片"); }]; [alert addAction:cancelAction]; [alert addAction:firstAction]; [alert addAction:destructiveAction]; [alert addAction:secondAction]; [self presentViewController:alert animated:YES completion:^{ nil; }];
比較上面的兩段代碼,能夠發現一些共同點:
UIAlertController使用alertControllerWithTitle:message:preferredStyle:
實例化一個對象。
都用到了UIAlertAction
類,和addAction:
方法。
都使用了presentViewController:animated:completion:
方法顯示。
其實,上述總結的共同點就是UIAlertController對象被實例化,而後添加每一個按鈕以及按鈕所須要響應的事件的一個過程。
+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle
這是UIAlertController的類方法,其中的preferredStyle
參數的值,決定了它顯示的樣式。若是是UIAlertControllerStyleAlert
,那麼會顯示一個alertView
。若是是UIAlertControllerActionSheet
,那麼會顯示一個actionSheet
。
這個類的做用就是給UIAlertController添加按鈕,以及按鈕所響應的事件。
+ (instancetype)actionWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(UIAlertAction *action))handler
在這個初始化方法中,style
參數指定按鈕顯示的樣式,而handler
這個Block裏放按鈕點擊後須要執行的操做。
style
這個參數能夠選擇3個值:
UIAlertActionStyleDefault。顯示常規的按鈕樣式。
UIAlertActionStyleCancel。顯示取消
按鈕的樣式,是加粗的。
UIAlertActionStyleDestructive。顯示紅色的文字。通常狀況下,表示這個按鈕點擊後可能會改變或者刪除數據。
在實例化UIAlertAction的對象以後,須要使用addAction:
方法,將他們添加到UIAlertController上。除了取消按鈕外,添加的順序決定了按鈕在UIAlertController上顯示的順序。
這個屬性值默認爲nil。
賦給這個屬性的alertAction必須已經添加到UIAlertController中,不然運行後會crash。設置以後,對應的按鈕的文字會被加粗顯示。_全部的按鈕的文字只有一個是加粗顯示的。_
- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler
這個方法能夠爲alertController添加一個文本框。這個方法所帶的block參數能夠用來設置文本框的樣式。這個方法能夠屢次被調用,被一次添加到UIAlertController中。
通常狀況下,咱們的App須要適配到iOS 7.0。因此,咱們依然可使用UIAlertView
和UIActionSheet
,而且,它們能夠在iOS 9.0以上的設備上運行的。話雖如此,進行適配確定會爲咱們規避不可預估的不良後果。
給你們推薦一個在iOS 8上使用UIAlertController的框架 —— GJAlertController。框架的做者郭曉亮爲你們講解了內部的實現方式,你們能夠參考《黑魔法——「低版本中使用高版本中出現的類」之技術實現原理詳解》。