本文最后更新于:2021年12月22日 中午
                
              
            
            
              由于UIAlertView在iOS 9中已经被废弃,我们找到UIAlertController来代替它来实现弹出框的功能。
UIAlertController 在iOS8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一种模块化替换的方式来代替这两货的功能和作用。是使用对话框(alert)还是使用上拉菜单(action sheet),就取决于在创建控制器时,您是如何设置首选样式的。
默认对话框 您可以比较一下两种不同的创建对话框的代码,创建基础UIAlertController的代码和创建UIAlertView的代码非常相似:
1 2 UIAlertController  *alertController = [UIAlertController  alertControllerWithTitle: @"标题" @"这个是UIAlertController的默认样式"  preferredStyle:UIAlertControllerStyleAlert ];
swift版本:
1 2 var  alertController =  UIAlertController (title:"标题" , message: "这个是UIAlertController的默认样式" , preferredStyle:UIAlertControllerStyle .Alert )
同创建UIAlertView相比,我们无需指定代理,也无需在初始化过程中指定按钮。不过要特别注意第三个参数,要确定您选择的是对话框样式还是上拉菜单样式。
1 2 3 4 5 6 7 UIAlertAction  *cancelAction = [UIAlertAction  actionWithTitle:@"取消" UIAlertActionStyleCancel  handler:nil ];UIAlertAction  *okAction = [UIAlertAction  actionWithTitle:@"好的" UIAlertActionStyleDefault  handler:nil ];
swift版本:
1 2 3 4 5 6 varcancelAction =  UIAlertAction (title:"取消" ,UIAlertActionStyle .Cancel , handler: nil )=  UIAlertAction (title:"好的" ,UIAlertActionStyle .Default , handler: nil )
最后,我们只需显示这个对话框视图控制器即可:
1 [self  presentViewController:alertController animated:YES  completion:nil ];
swift版本:
1 self .presentViewController(alertController, animated:true , completion: nil )
按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,根据苹果官方制定的《iOS 用户界面指南》,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
1 2 3 *Terminating app due to uncaught exceptionNSInternalInconsistencyException ’, reason: ‘UIAlertController  can onlyUIAlertActionStyleCancel ’
“警示”样式 什么是“警示”样式呢?我们先不着急回答这个问题,先来看一下下面关于“警示”样式的简单示例。在这个示例中,我们将前面的示例中的“好的”按钮替换为了“重置”按钮。
1 2 3 UIAlertAction  *resetAction = [UIAlertAction  actionWithTitle:@"重置" UIAlertActionStyleDestructive  handler:nil ];
swift版本:
1 2 3 var  resetAction =  UIAlertAction (title:"重置" ,UIAlertActionStyle .Destructive , handler: nil )
可以看出,我们新增的那个“重置”按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。
文本对话框 UIAlertController
1 2 3 4 5 6 7 8 9 10 11 12 13 UIAlertController  *alertController = [UIAlertController  alertControllerWithTitle:@"文本对话框" message:@"登录和密码对话框示例" UIAlertControllerStyleAlert ];UITextField  *textField){@"登录" ;UITextField  *textField) {@"密码" ;YES ;
swift版本:
1 2 3 4 5 6 7 8 9 10 alertController.addTextFieldWithConfigurationHandler {UITextField !) -> Voidin = "登录" UITextField !) -> Voidin = "密码" = true 
在“好的”按钮按下时,我们让程序读取文本框中的值。
1 2 3 4 5 6 7 UIAlertAction  *okAction = [UIAlertAction  actionWithTitle:@"好的" style:UIAlertActionStyleDefault  handler:UIAlertAction  *action) {UITextField  *login = alertController.textFields.firstObject;UITextField  *password = alertController.textFields.lastObject;
swift版本:
1 2 3 4 5 var  okAction =  UIAlertAction (title:"好的" , style: UIAlertActionStyle .Default ) {UIAlertAction !) -> Voidin var  login =  alertController.textFields? .first as  UITextField var  password =  alertController.textFields? .last as  UITextField 
如果我们想要实现UIAlertView中的委托方法alertViewShouldEnableOtherButton:方法的话可能会有一些复杂。假定我们要让“登录”文本框中至少有3个字符才能激活“好的”按钮。很遗憾的是,在UIAlertController中并没有相应的委托方法,因此我们需要向“登录”文本框中添加一个Observer。Observer模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。我们可以在构造代码块中添加如下的代码片段来实现。
1 2 3 4 5 6 7 [alertController addTextFieldWithConfigurationHandler:UITextField  *textField){NSNotificationCenter  defaultCenter] addObserver:self @selector (alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification  object:textField];
swift版本:
1 2 3 4 5 6 7 alertController.addTextFieldWithConfigurationHandler {UITextField !) -> Void  in ... NSNotificationCenter .defaultCenter().addObserver(self , selector:Selector ("alertTextFieldDidChange:" ), name:UITextFieldTextDidChangeNotification , object: textField)
当视图控制器释放的时候我们需要移除这个Observer,我们通过在每个按钮动作的handler代码块(还有其他任何可能释放视图控制器的地方)中添加合适的代码来实现它。比如说在okAction这个按钮动作中:
1 2 3 4 5 6 7 UIAlertAction  *okAction = [UIAlertAction  actionWithTitle:@"好的" style:UIAlertActionStyleDefault  handler:UIAlertAction  *action) {NSNotificationCenter  defaultCenter] removeObserver:self UITextFieldTextDidChangeNotification  object:nil ];
swift版本:
1 2 3 4 5 6 var  okAction =  UIAlertAction (title:"好的" , style: UIAlertActionStyle .Default ) {UIAlertAction !) -> Void  in ... NSNotificationCenter .defaultCenter().removeObserver(self , name:UITextFieldTextDidChangeNotification , object: nil )
在显示对话框之前,我们要冻结“好的”按钮
swift版本:
接下来,在通知观察者(notification observer)中,我们需要在激活按钮状态前检查“登录”文本框的内容。
1 2 3 4 5 6 7 8 9 10 - (void )alertTextFieldDidChange:(NSNotification  *)notification{UIAlertController  *alertController =UIAlertController  *)self .presentedViewController;if (alertController) {UITextField  *login = alertController.textFields.firstObject;UIAlertAction  *okAction = alertController.actions.lastObject;2 ;
swift版本:
1 2 3 4 5 6 7 8 func  alertTextFieldDidChange (notification : NSNotification )var  alertController =  self .presentedViewController as  UIAlertController ?if (alertController !=  nil ) {var  login =  alertController! .textFields? .first as  UITextField var  okAction =  alertController! .actions.last as  UIAlertAction =  countElements(login.text) >  2 
好了,现在对话框的“好的”按钮被冻结了,输入3个以上的字符“登录”文本框才能点击“好的”。
上拉菜单 当需要给用户展示一系列选择的时候(选择恐惧症患者杀手),上拉菜单就能够派上大用场了。和对话框不同,上拉菜单的展示形式和设备大小有关。在iPhone上(紧缩宽度),上拉菜单从屏幕底部升起。在iPad上(常规宽度),上拉菜单以弹出框的形式展现。
1 2 3 UIAlertController  *alertController = [UIAlertController  alertControllerWithTitle:@"保存或删除数据" message:@"删除数据将不可恢复" UIAlertControllerStyleActionSheet ];
swift版本:
1 2 3 varalertController =  UIAlertController (title:"保存或删除数据" ,"删除数据将不可恢复" ,UIAlertControllerStyle .ActionSheet )
添加按钮动作的方式和对话框相同。
1 2 3 4 5 6 7 8 9 10 UIAlertAction  *cancelAction = [UIAlertAction  actionWithTitle:@"取消" UIAlertActionStyleCancel  handler:nil ];UIAlertAction  *deleteAction = [UIAlertAction  actionWithTitle:@"删除" UIAlertActionStyleDestructive  handler:nil ];UIAlertAction  *archiveAction = [UIAlertAction  actionWithTitle:@"保存" UIAlertActionStyleDefault  handler:nil ];
swift版本:
1 2 3 4 5 6 7 8 9 10 varcancelAction =  UIAlertAction (title:"取消" ,UIAlertActionStyle .Cancel , handler: nil )=  UIAlertAction (title:"删除" ,UIAlertActionStyle .Destructive , handler: nil )=  UIAlertAction (title:"保存" ,UIAlertActionStyle .Default , handler: nil )
您不能在上拉菜单中添加文本框,如果您强行作死添加了文本框,那么就会荣幸地得到一个运行时异常:
1 2 3 *Terminating app due to uncaught exceptionNSInternalInconsistencyException ’, reason: ‘Text fields can only beUIAlertControllerStyleAlert ’
同样,简单的异常说明,我们也不多说了。
1 [self  presentViewController:alertController animated:YES  completion:nil ];
swift版本:
1 self .presentViewController(alertController, animated:true , completion: nil )
如果上拉菜单中有“取消”按钮的话,那么它永远都会出现在菜单的底部,不管添加的次序是如何(就是这么任性)。其他的按钮将会按照添加的次序从上往下依次显示。《iOS 用户界面指南》要求所有的“毁坏”样式按钮都必须排名第一(红榜嘛,很好理解的,对不对?)。
1 2 3 4 5 Terminating app due to uncaught exception ‘NSGenericException ’, reason:UIPopoverPresentationController 0x7fc619588110 ="" >) should have a non-nil  sourceView or barButtonItem
就如我们之前所说,在常规宽度的设备上,上拉菜单是以弹出框的形式展现。弹出框必须要有一个能够作为源视图或者栏按钮项目的描点(anchor point)。由于在本例中我们是使用了常规的UIButton来触发上拉菜单的,因此我们就将其作为描点。
1 2 3 4 5 6 7 UIPopoverPresentationController  *popover =if (popover){UIPopoverArrowDirectionAny ;
swift版本:
1 2 3 4 5 6 var  popover =  alertController.popoverPresentationControllerif (popover !=  nil ){? .sourceView =  sender? .sourceRect =  sender.bounds? .permittedArrowDirections =  UIPopoverArrowDirection .Any 
UIPopoverPresentationController类同样也是在iOS 8中新出现的类,用来替换UIPopoverController的。这个时候上拉菜单是以一个固定在源按钮上的弹出框的形式显示的。
释放对话框控制器 通常情况下,当用户选中一个动作后对话框控制器将会自行释放。不过您仍然可以在需要的时候以编程方式释放它,就像释放其他视图控制器一样。您应当在应用程序转至后台运行时移除对话框或者上拉菜单。假定我们正在监听UIApplicationDidEnterBackgroundNotification通知消息,我们可以在observer中释放任何显示出来的视图控制器。(参考在viewDidLoad方法中设立observer的示例代码)。
1 2 3 4 5 6 - (void )didEnterBackground:(NSNotification  *)notification {NSNotificationCenter  defaultCenter] removeObserver:self UITextFieldTextDidChangeNotification  object:nil ];self .presentedViewController dismissViewControllerAnimated:NO nil ];
swift版本:
1 2 3 4 5 6 func  didEnterackground (notification : NSNotification )NSNotificationCenter .defaultCenter().removeObserver(self ,UITextFieldTextDidChangeNotification , object: nil )self .presentedViewController? .dismissViewControllerAnimated(false ,nil )
注意,要保证运行安全我们同样要确保移除所有的文本框observer。
附上以前我们使用UIAlertView实现的一些功能:
UIAlertView 初始化和显示一个带有“取消”和“好的”按钮的对话框视图。
1 2 3 4 UIAlertView  *alertview = [[UIAlertView  alloc] initWithTitle:@"标题" @"这个是UIAlertView的默认样式" delegate:self  cancelButtonTitle:@"取消" @"好的" , nil ];
swift版本和Objective-C版本不同,在swift中,alertView的初始化只允许创建拥有一个取消按钮的对话框视图。或许您可以看到带有otherButtonTitles的init方法,但是很遗憾,这个方法是没有办法通过编译的。
1 2 3 var alertView = UIAlertView (title:"标题" , message:"这个是UIAlertView的默认样式" ,self , cancelButtonTitle:"取消" )
要能够创建和上面Objective-C版本相同的对话框视图,我们可以采取曲线救国的方法,虽然麻烦了些,但是我们为了目的可以不择手段的,是吧?
1 2 3 4 5 6 7 varalertView = UIAlertView ()self "标题" "这个是UIAlertView的默认样式" "取消" )"好的" )
您也可以通过更改UIAlertView的alertViewStyle属性来实现输入文字、密码甚至登录框的效果。
UIAlertViewDelegate协议拥有响应对话框视图的按钮动作的回调方法。还有当文本框内容改变时,调用alertViewShouldEnableOtherButton:方法可以让按钮动态地可用或者不可用。
联系方式 邮箱:  xiebangyao_1994@163.com 相关账号: