从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。框架的做者郭晓亮为你们讲解了内部的实现方式,你们能够参考《黑魔法——“低版本中使用高版本中出现的类”之技术实现原理详解》

相关文章
相关标签/搜索