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