iOS 8的新特性之一就是让接口更有适应性、更灵活,因此许多视图控制器的实现方式发生了巨大的变化。全新UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸变化效果(比如说旋转)中发挥了重要的作用,它有效地节省了程序员们的工作量。还有,某些旧的UIKit控件也同样发生了许多变化,比如说Alert Views、Action Sheets、Popovers以及Search Bar Controllers。
之前,我们是通过UIAlertView
来实现对话框效果的,要说明一点,苹果官方现在并不提倡在iOS 8中使用UIAlertView,取而代之的是UIAlertController。下面我们就来介绍UIAlertController的使用方法。
UIAlertController
在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一种模块化替换的方式来代替这两货的功能和作用。是使用对话框(alert)还是使用上拉菜单(action sheet),就取决于在创建控制器时,您是如何设置首选样式的。
1.一个简单的对话框例子
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"标题" message:@"这个是UIAlertController的默认样式" preferredStyle:UIAlertControllerStyleAlert];
同创建UIAlertView相比,我们无需指定代理,也无需在初始化过程中指定按钮。不过要特别注意第三个参数,要确定您选择的是对话框样式还是上拉菜单样式。
通过创建UIAlertAction的实例,您可以将动作按钮添加到控制器上。UIAlertAction由标题字符串、样式以及当用户选中该动作时运行的代码块组成。通过UIAlertActionStyle,您可以选择如下三种动作样式:常规(default)、取消(cancel)以及警示(destruective)。为了实现原来我们在创建UIAlertView时创建的按钮效果,我们只需创建这两个动作按钮并将它们添加到控制器上即可。
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
最后,我们只需显示这个对话框视图控制器即可:
[self presentViewController:alertController animated:YES completion:nil];
按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,根据苹果官方制定的《iOS 用户界面指南》,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’
2.“警示”样式
什么是“警示”样式呢?我们先不着急回答这个问题,先来看一下下面关于“警示”样式的简单示例。在这个示例中,我们将前面的示例中的“好的”按钮替换为了“重置”按钮。
UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"重置" style:UIAlertActionStyleDestructive handler:nil];
[alertController addAction:resetAction];
可以看出,我们新增的那个“重置”按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。
3.文本对话框
UIAlertController极大的灵活性意味着您不必拘泥于内置样式。以前我们只能在默认视图、文本框视图、密码框视图、登录和密码输入框视图中选择,现在我们可以向对话框中添加任意数目的UITextField对象,并且可以使用所有的UITextField特性。当您向对话框控制器中添加文本框时,您需要指定一个用来配置文本框的代码块。
举个栗子吧,要重新建立原来的登录和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,最后将密码输入框设置使用安全文本输入。
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"文本对话框" message:@"登录和密码对话框示例" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
textField.placeholder = @"登录";
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = @"密码";
textField.secureTextEntry = YES;
}];
在“好的”按钮按下时,我们让程序读取文本框中的值。
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
UITextField *login = alertController.textFields.firstObject;
UITextField *password = alertController.textFields.lastObject;
...
}];
上拉菜单
当需要给用户展示一系列选择的时候(选择恐惧症患者杀手),上拉菜单就能够派上大用场了。和对话框不同,上拉菜单的展示形式和设备大小有关。在iPhone上(紧缩宽度),上拉菜单从屏幕底部升起。在iPad上(常规宽度),上拉菜单以弹出框的形式展现。
创建上拉菜单的方式和创建对话框的方式非常类似,唯一的区别是它们的形式。
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"保存或删除数据" message:@"删除数据将不可恢复" preferredStyle: UIAlertControllerStyleActionSheet];
添加按钮动作的方式和对话框相同。
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"删除" style:UIAlertActionStyleDestructive handler:nil];
UIAlertAction *archiveAction = [UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:deleteAction];
[alertController addAction:archiveAction];
您不能在上拉菜单中添加文本框,如果您强行作死添加了文本框,那么就会荣幸地得到一个运行时异常:
* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert’
接下来我们就可以在iPhone或者其他紧缩宽度的设备上展示了,不出我们所料,运行得很成功。
[self presentViewController:alertController animated:YES completion:nil];
如果上拉菜单中有“取消”按钮的话,那么它永远都会出现在菜单的底部,不管添加的次序是如何(就是这么任性)。其他的按钮将会按照添加的次序从上往下依次显示。《iOS 用户界面指南》要求所有的“毁坏”样式按钮都必须排名第一
别激动得太早,我们现在还有一个很严重的问题,这个问题隐藏得比较深。当我们使用iPad或其他常规宽度的设备时,就会得到一个运行时异常:
Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘UIPopoverPresentationController (<_uialertcontrolleractionsheetregularpresentationcontroller: 0x7fc619588110="">) should have a non-nil sourceView or barButtonItem set before the presentation occurs.’
就如我们之前所说,在常规宽度的设备上,上拉菜单是以弹出框的形式展现。弹出框必须要有一个能够作为源视图或者栏按钮项目的描点(anchor point)。由于在本例中我们是使用了常规的UIButton来触发上拉菜单的,因此我们就将其作为描点。