随着苹果上次iOS 5的发布,对话框视图样式出现在了我们面前,直到现在它都没有发生过很大的变化。下面的代码片段展示了如何初始化和显示一个带有“取消”和“好的”按钮的对话框视图。
Objective-C版本:
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:@"标题" message:@"这个是UIAlertView的默认样式" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil]; [alertview show];
swift版本和Objective-C版本不同,在swift中,alertView的初始化只允许创建拥有一个取消按钮的对话框视图。或许您可以看到带有otherButtonTitles
的init方法,但是很遗憾,这个方法是没有办法通过编译的。
var alertView = UIAlertView(title: "标题", message: "这个是UIAlertView的默认样式", delegate: self, cancelButtonTitle: "取消") alertView.show()
要能够创建和上面Objective-C版本相同的对话框视图,我们可以采取曲线救国的方法,虽然麻烦了些,但是我们为了目的可以不择手段的,是吧?
var alertView = UIAlertView() alertView.delegate = selfalertView.title = "标题"alertView.message = "这个是UIAlertView的默认样式"alertView.addButtonWithTitle("取消") alertView.addButtonWithTitle("好的") alertView.show()
您也可以通过更改UIAlertView
的alertViewStyle
属性来实现输入文字、密码甚至登录框的效果。
UIAlertViewDelegate
协议拥有响应对话框视图的按钮动作的回调方法。还有当文本框内容改变时,调用alertViewShouldEnableOtherButton:
方法可以让按钮动态地可用或者不可用。
要说明一点,苹果官方现在并不提倡在iOS 8中使用UIAlertView
,取而代之的是UIAlertController
。下面我们就来介绍UIAlertController
的使用方法。
在iOS 8中,UIAlertController
在功能上是和UIAlertView
以及UIActionSheet
相同的,UIAlertController
以一种模块化替换的方式来代替这两货的功能和作用。是使用对话框(alert)还是使用上拉菜单(action sheet),就取决于在创建控制器时,您是如何设置首选样式的。
您可以比较一下两种不同的创建对话框的代码,创建基础UIAlertController
的代码和创建UIAlertView
的代码非常相似:
Objective-C版本:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"标题" message:@"这个是UIAlertController的默认样式" preferredStyle:UIAlertControllerStyleAlert];
swift版本:
var alertController = UIAlertController(title: "标题", message: "这个是UIAlertController的默认样式", preferredStyle: UIAlertControllerStyle.Alert)
同创建UIAlertView
相比,我们无需指定代理,也无需在初始化过程中指定按钮。不过要特别注意第三个参数,要确定您选择的是对话框样式还是上拉菜单样式。
通过创建UIAlertAction
的实例,您可以将动作按钮添加到控制器上。UIAlertAction
由标题字符串、样式以及当用户选中该动作时运行的代码块组成。通过UIAlertActionStyle
,您可以选择如下三种动作样式:常规(default)、取消(cancel)以及警示(destruective)。为了实现原来我们在创建UIAlertView
时创建的按钮效果,我们只需创建这两个动作按钮并将它们添加到控制器上即可。
Objective-C版本:
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil]; [alertController addAction:cancelAction]; [alertController addAction:okAction];
swift版本:
var cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.Cancel, handler: nil) var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default, handler: nil) alertController.addAction(cancelAction) alertController.addAction(okAction)
最后,我们只需显示这个对话框视图控制器即可:
Objective-C版本:
[self presentViewController:alertController animated:YES completion:nil];
swift版本:
self.presentViewController(alertController, animated: true, completion: nil)
按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,根据苹果官方制定的《iOS 用户界面指南》,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’
异常信息简洁明了,我们在此就不赘述了。
什么是“警示”样式呢?我们先不着急回答这个问题,先来看一下下面关于“警示”样式的简单示例。在这个示例中,我们将前面的示例中的“好的”按钮替换为了“重置”按钮。
Objective-C版本:
UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"重置" style:UIAlertActionStyleDestructive handler:nil]; [alertController addAction:resetAction];
swift版本:
var resetAction = UIAlertAction(title: "重置", style: UIAlertActionStyle.Destructive, handler: nil) alertController.addAction(resetAction)
“警示”样式
可以看出,我们新增的那个“重置”按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。
UIAlertController
极大的灵活性意味着您不必拘泥于内置样式。以前我们只能在默认视图、文本框视图、密码框视图、登录和密码输入框视图中选择,现在我们可以向对话框中添加任意数目的UITextField
对象,并且可以使用所有的UITextField
特性。当您向对话框控制器中添加文本框时,您需要指定一个用来配置文本框的代码块。
举个栗子吧,要重新建立原来的登录和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,最后将密码输入框设置使用安全文本输入。
Objective-C版本:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"文本对话框" message:@"登录和密码对话框示例" preferredStyle:UIAlertControllerStyleAlert]; [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){ textField.placeholder = @"登录"; }]; [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { textField.placeholder = @"密码"; textField.secureTextEntry = YES; }];
swift版本:
alertController.addTextFieldWithConfigurationHandler { (textField: UITextField!) -> Void in textField.placeholder = "登录"} alertController.addTextFieldWithConfigurationHandler { (textField: UITextField!) -> Void in textField.placeholder = "密码" textField.secureTextEntry = true}
在“好的”按钮按下时,我们让程序读取文本框中的值。
Objective-C版本:
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { UITextField *login = alertController.textFields.firstObject; UITextField *password = alertController.textFields.lastObject; ... }];
swift版本:
var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default) { (action: UIAlertAction!) -> Void in var login = alertController.textFields?.first as UITextField var password = alertController.textFields?.last as UITextField}
如果我们想要实现UIAlertView
中的委托方法alertViewShouldEnableOtherButton:
方法的话可能会有一些复杂。假定我们要让“登录”文本框中至少有3个字符才能激活“好的”按钮。很遗憾的是,在UIAlertController
中并没有相应的委托方法,因此我们需要向“登录”文本框中添加一个Observer。Observer模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。我们可以在构造代码块中添加如下的代码片段来实现。
Objective-C版本:
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){ ... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification object:textField];}];
swift版本:
alertController.addTextFieldWithConfigurationHandler { (textField: UITextField!) -> Void in ... NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("alertTextFieldDidChange:"), name: UITextFieldTextDidChangeNotification, object: textField) }
当视图控制器释放的时候我们需要移除这个Observer,我们通过在每个按钮动作的handler代码块(还有其他任何可能释放视图控制器的地方)中添加合适的代码来实现它。比如说在okAction这个按钮动作中:
Objective-C版本:
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { ... [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil]; }];
swift版本:
var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default) { (action: UIAlertAction!) -> Void in ... NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil) }
在显示对话框之前,我们要冻结“好的”按钮
Objective-C版本:
okAction.enabled = NO;
swift版本:
okAction.enabled = false
接下来,在通知观察者(notification observer)中,我们需要在激活按钮状态前检查“登录”文本框的内容。
Objective-C版本:
- (void)alertTextFieldDidChange:(NSNotification *)notification{ UIAlertController *alertController = (UIAlertController *)self.presentedViewController; if (alertController) { UITextField *login = alertController.textFields.firstObject; UIAlertAction *okAction = alertController.actions.lastObject; okAction.enabled = login.text.length > 2; } }
swift版本:
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 okAction.enabled = countElements(login.text) > 2 } }
UIAlertController的登录和密码对话框示例
好了,现在对话框的“好的”按钮被冻结了,除非在“登录”文本框中输入3个以上的字符: