從UIAlertView、UIActionSheet到UIAlertController

文章更新:
3月9日:推薦一個開源框架GJAlertControllergit

許多時候,咱們須要在應用中彈出提示框,給用戶提示信息,而後讓用戶選擇執行哪一種操做。有兩種形式,一種是彈出提示框,一種是彈出提示菜單。github

  • 提示框:進入Apple Music,在登陸時,會彈出提示輸入AppleID帳戶和密碼的提示框。
    image框架

  • 提示菜單:在Apple Music中,選擇將一首歌曲加入到播放列表時,彈出以下菜單。
    imageatom

UIAlertView

在iOS 9.0中,UIAlertView被棄用。固然,UIAlertViewDelegate一樣被棄用。取而代之的是,使用UIAlertController,初始化時,將preferredStyle設爲UIAlertControllerStyleAlertspa

初始化UIAlertView

使用代理

- (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];

效果以下:
image索引

若是otherButtonTitles參數有多個NSString時,效果以下:
image

咱們也可使用

- (NSInteger)addButtonWithTitle:(NSString *)title

來添加UIAlertView所顯示的按鈕。

@property(nonatomic, copy) NSString *title
@property(nonatomic, copy) NSString *message

能夠設置這兩個屬性改變titlemessage

不建議添加太多的按鈕,不然會下降用戶體驗。

代理方法

在初始化方法中有參數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對應索引0other1對應索引1other2對應索引2

alertView的樣式

咱們能夠經過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

UIActionSheet和UIActionSheetDelegate在iOS 8.3中被棄用。取代它的是preferredStyle被設爲UIAlertControllerStyleActionSheetUIAlertController

在我使用App的過程當中,兩種狀況下使用UIActionSheet。

  • 當用戶刪除東西的時候,給出提示;

  • 在上傳頭像時,選擇用相機拍照仍是相冊照片。

初始化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];

image

destructiveButtonTitleotherButtonTitles根據狀況傳值,二選一,不然就會像上圖所顯示的那樣,看起來很醜!

代理方法

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和UIActionSheet

這兩個的類的屬性、方法、代理都極其類似。

須要注意的是,當它們都有多個按鈕時,計算按鈕索引的方法是不一樣的。

  • UIAlertView的取消按鈕的索引永遠是0,其餘的依次+1。

  • UIActionSheet的索引是全部的按鈕從上到下,從0開始,一次+1。

- (void)alertViewCancel:(UIAlertView *)alertView
- (void)actionSheetCancel:(UIActionSheet *)actionSheet

這兩個代理方法在什麼狀況下會調用,我沒有搞清楚!

UIAlertController

到了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;
}];

image

//實現和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;
}];

image

比較上面的兩段代碼,能夠發現一些共同點:

  • 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

UIAlertAction

這個類的做用就是給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上顯示的順序。

只能在UIAlertControllerStyleAlert下使用的一些特殊的設置

preferredAction

這個屬性值默認爲nil。

賦給這個屬性的alertAction必須已經添加到UIAlertController中,不然運行後會crash。設置以後,對應的按鈕的文字會被加粗顯示。_全部的按鈕的文字只有一個是加粗顯示的。_

文本輸入框

- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler

這個方法能夠爲alertController添加一個文本框。這個方法所帶的block參數能夠用來設置文本框的樣式。這個方法能夠屢次被調用,被一次添加到UIAlertController中。

結語

通常狀況下,咱們的App須要適配到iOS 7.0。因此,咱們依然可使用UIAlertViewUIActionSheet,而且,它們能夠在iOS 9.0以上的設備上運行的。話雖如此,進行適配確定會爲咱們規避不可預估的不良後果。

給你們推薦一個在iOS 8上使用UIAlertController的框架 —— GJAlertController。框架的做者郭曉亮爲你們講解了內部的實現方式,你們能夠參考《黑魔法——「低版本中使用高版本中出現的類」之技術實現原理詳解》

相關文章
相關標籤/搜索