IOS之UIAlertController
你知道 UIAlertView
、UIActionSheet
(以及它们各自的 delegate protocols) 在 iOS 8 中已经被废弃了吗?
这是真的。在你的代码中按住 ⌘ 点击 UIAlertView
或者 UIActionSheet
,你就会看到最上面的注释:
UIAlertView
is deprecated. UseUIAlertController
with apreferredStyle
ofUIAlertControllerStyleAlert
instead.
你可能好奇为什么 Xcode 不直接警告你这个变化呢?别急,往下读:
@availability(iOS, introduced=2.0)
虽然类已经被废弃了,但在 @availability
属性中并没有表达出这一点。UIAlertView
目前还是能用的。
最开始的时候,UIAlertView
充满了无底线的让步,牺牲格式和设计正确性来顺应开发者的喜好。它的 delegate
类型是在初始化函数中注释的 (delegate:(id /* <UIAlertViewDelegate */)delegate
),并且在 protocol 方法中实现了让人匪夷所思的概念——buttonAtIndex:
的 "clicked" 而不是 "tapped";然后还提供了不限数量的参数来引入 otherButtonTitles
,因此 button 的索引管理变得非常痛苦;一个 -show
方法也根本不考虑 view 的层级关系......类似的问题数不胜数。
UIActionSheet
也一样糟糕,但是开发者大多数时间里都没时间想起那些糟糕的使用方法,与其相关的抱怨特就更少了。
因此,介绍 UIAlertController
给大家,就好比派出军队解放一座被占领的城市一样。它不仅仅改进了那些让人头疼的 API,也开辟了一条为最新设备上 UIKit 特性适配的新路径。
本周文章的主题就是 UIAlertController
,向大家展示如何替换旧的 alert,以及这些操作方法的高级扩展。
UIAlertController
同时替代了 UIAlertView
和 UIActionSheet
,从系统层级上统一了 alert 的概念 —— 即以 modal 方式或 popover 方式展示。
UIAlertController
是 UIViewController
的子类,而非其先前的方式。因此新的 alert 可以由 view controller 展示相关的配置中获益很多。
UIAlertController
不管是要用 alert 还是 action sheet 方式展示,都要以 title
和 message
参数来初始化。Alert 会在当前显示的 view controller 中心以模态形式出现,action sheet 则会在底部滑出。Alert 可以同时有按钮和输入框,action sheet 仅支持按钮。
新的方式并没有把所有的 alert 按钮配置都放在初始化函数中,而是引入了一个新类 UIAlertAction
的对象,在初始化之后可以进行配置。这种形式的 API 重构让对按钮数量、类型、顺序方便有了更大的控制。同时也弃用了 UIAlertView
和 UIActionSheet
使用的delegate 这种方式,而是采用更简便的完成时回调。
新旧 Alert 方式对比
标准的 Alert 样式
旧方法:UIAlertView
let alertView = UIAlertView(title: "Default Style", message: "A standard alert.", delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "OK")
alertView.alertViewStyle = .Default
alertView.show()
// MARK: UIAlertViewDelegate
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
switch buttonIndex {
// ...
}
}
新方法:UIAlertController
let alertController = UIAlertController(title: "Default Style", message: "A standard alert.", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
// ...
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) {
// ...
}
标准的 Action Sheet 样式
UIActionSheet
let actionSheet = UIActionSheet(title: "Takes the appearance of the bottom bar if specified; otherwise, same as UIActionSheetStyleDefault.", delegate: self, cancelButtonTitle: "Cancel", destructiveButtonTitle: "Destroy", otherButtonTitles: "OK")
actionSheet.actionSheetStyle = .Default
actionSheet.showInView(self.view)
// MARK: UIActionSheetDelegate
func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
switch buttonIndex {
...
}
}
UIAlertController
let alertController = UIAlertController(title: nil, message: "Takes the appearance of the bottom bar if specified; otherwise, same as UIActionSheetStyleDefault.", preferredStyle: .ActionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
// ...
}
alertController.addAction(OKAction)
let destroyAction = UIAlertAction(title: "Destroy", style: .Destructive) { (action) in
println(action)
}
alertController.addAction(destroyAction)
self.presentViewController(alertController, animated: true) {
// ...
}
新功能
UIAlertController
并不只是对已有的 API 做了清理,而是进行了标准化归纳。以前,预设的样式闲置有很多(swizzling 虽然可以提供更多的功能但还是有很大风险)。UIAlertController
让以前看起来很神奇的事情变为了可能。
UIAlertController
is not just a cleanup of pre-existing APIs, it's a generalization of them. Previously, one was constrained to whatever presets were provided (swizzling in additional functionality at their own risk). With UIAlertController
, it's possible to do a lot more out-of-the-box:
带有警示按钮的 Alert
这种行为已经被 UIAlertActionStyle
所涵盖,共有三种类型:
.Default
: 对按钮应用标准样式。.Cancel
: 对按钮应用取消样式,代表取消操作不做任何改变。.Destructive
: 对按钮应用警示性的样式,提示用户这样做可能会改变或删除某些数据。
所以想要对模态的 alert 加一个警示性的按钮,只需要加上 .Destructive
风格的 UIAlertAction
属性:
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
println(action)
}
alertController.addAction(cancelAction)
let destroyAction = UIAlertAction(title: "Destroy", style: .Destructive) { (action) in
println(action)
}
alertController.addAction(destroyAction)
self.presentViewController(alertController, animated: true) {
// ...
}
大于 2 个按钮的 Alert
有 1 个或者 2 个操作的时候,按钮会水平排布。更多按钮的情况,就会像 action sheet 那样展示:
let oneAction = UIAlertAction(title: "One", style: .Default) { (_) in }
let twoAction = UIAlertAction(title: "Two", style: .Default) { (_) in }
let threeAction = UIAlertAction(title: "Three", style: .Default) { (_) in }
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (_) in }
alertController.addAction(oneAction)
alertController.addAction(twoAction)
alertController.addAction(threeAction)
alertController.addAction(cancelAction)
创建登录表单
iOS 5 就为 UIAlertView
加入了 alertViewStyle
属性,将原本私有的 API 暴露出来给开发者使用 —— 像某些系统内建应用一样允许在 alert 中显示登录和密码框。
在 iOS 8 中,UIAlertController
则加入了 addTextFieldWithConfigurationHandler
方法:
let loginAction = UIAlertAction(title: "Login", style: .Default) { (_) in
let loginTextField = alertController.textFields![0] as UITextField
let passwordTextField = alertController.textFields![1] as UITextField
login(loginTextField.text, passwordTextField.text)
}
loginAction.enabled = false
let forgotPasswordAction = UIAlertAction(title: "Forgot Password", style: .Destructive) { (_) in }
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (_) in }
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Login"
NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification, object: textField, queue: NSOperationQueue.mainQueue()) { (notification) in
loginAction.enabled = textField.text != ""
}
}
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Password"
textField.secureTextEntry = true
}
alertController.addAction(loginAction)
alertController.addAction(forgotPasswordAction)
alertController.addAction(cancelAction)
创建注册表单
UIAlertController
想得比以前更周到一些,它提供了展示无限个输入框的权限,并且每一个输入框都可以根据需求进行自定义。这让仅在一个模态的 alert 中实现完善的注册功能成为可能:
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Email"
textField.keyboardType = .EmailAddress
}
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Password"
textField.secureTextEntry = true
}
alertController.addTextFieldWithConfigurationHandler { (textField) in
textField.placeholder = "Password Confirmation"
textField.secureTextEntry = true
}
虽然有了这些,但必须要说明的是,不用矫枉过正。不能因为你可以这样做,就代表你应该这样做。忘了这玩意吧,提供一个 view controller 来做注册功能吧,因为你本就应该这样做!
注意
如果试图向 alert controller 添加带有 .ActionSheet
属性的输入框,将会抛出异常:
Terminating app due to uncaught exception
NSInternalInconsistencyException
, reason: 'Text fields can only be added to an alert controller of styleUIAlertControllerStyleAlert
'
同样的,向 alert 或 action sheet 添加一个以上的 .Cancel
按钮将会抛出异常:
Terminating app due to uncaught exception
NSInternalInconsistencyException
, reason: 'UIAlertController
can only have one action with a style ofUIAlertActionStyleCancel
'
IOS之UIAlertController的更多相关文章
- iOS Container View Controller
一.UIViewController 做iOS开发的经常会和UIViewController打交道,从类名可知UIViewController属于MVC模型中的C(Controller),说的更具体点 ...
- IOS Note - View Controller(视图控制器)
Application Delegate(应用程序委托) Application Name: SingleView SingleViewAppDelegate.h #import <UIKit/ ...
- 唐巧的iOS技术博客选摘
1. 那些被遗漏的objective-c保留字:http://blog.devtang.com/blog/2013/04/29/the-missing-objc-keywords/ 2. 使用cr ...
- 《iOS开发全然上手——使用iOS 7和Xcode 5开发移动与平板应用》之Objective-C新手训练营
编写Hello World应用程序通常被觉得,是学习不论什么编程语言的第一步.在这一章,你将创建iOS版的Hello World应用程序作为起步,高速了解Xcode这个开发iOS应用程序的主要工具. ...
- iOS 中关于ViewController总结
以前写程序时,经常被旋转问题弄的头疼,今天为了解决这个问题,偶然看到了苹果官方文档 View Controller Programming Guide for iOS. 这才发现这个必读的资料!以前许 ...
- 【IOS笔记】About Events in iOS
About Events in iOS Users manipulate their iOS devices in a number of ways, such as touching the scr ...
- 《iOS 11 安全区域适配总结》
本文来自于腾讯Bugly公众号(weixinBugly),作者:sonialiu,未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/W1_0VrchCO50owhJ ...
- iOS移动开发周报-第17期
lhq iOS移动开发周报-第17期 前言 欢迎国内的iOS同行或技术作者向我提交周报线索,线索可以是新闻.教程.开发工具或开源项目,将相关文章的简介和链接在微博上发布并 @唐巧_boy 即可. [摘 ...
- Event Handling Guide for iOS--(一)--About Events in iOS
About Events in iOS Users manipulate their iOS devices in a number of ways, such as touching the scr ...
随机推荐
- 《Linux内核修炼之道》精华分享与讨论(5)——Kernel地图:Kconfig与Makefile
转自:http://blog.csdn.net/fudan_abc/article/details/5340408 Makefile不是Make Love 从前在学校,混了四年,没有学到任何东西,每天 ...
- 极客时间_Vue开发实战_06.Vue组件的核心概念(2):事件
06.Vue组件的核心概念(2):事件 通过emit传递给父组件 我们点击了重置失败,上层的div的click=handleDivClick是接收不到.重置失败的点击的行为的 通常情况下,你不用.st ...
- 2-1赋值运算符 & 2-2自增自减运算符 &2-3
2-1赋值运算符 先定义一个变量,把定义好的变量在赋值给另外一个变量.变向之间的互相赋值 2-2自增自减运算符 元素符,放在变量前和变量后的区别 先进行自增运算,再进行赋值运算.这里先进行num1的+ ...
- UVaLive 3902 Network (无根树转有根树,贪心)
题意:一个树形网络,叶子是客户端,其他的是服务器.现在只有一台服务器提供服务,使得不超k的客户端流畅,但是其他的就不行了, 现在要在其他结点上安装服务器,使得所有的客户端都能流畅,问最少要几台. 析: ...
- MFC的CString使用
CString没有基类.一个CString对象由可变长度的一队字符组成.CString使用类似于Basic的语法提供函数和操作符.连接和比较操作符以及简化的内存管理使CString对象比普通字符串数组 ...
- 一种Unity2D多分辨率屏幕适配方案
http://www.cnblogs.com/flyFreeZn/p/4073655.html 此文将阐述一种简单有效的Unity2D多分辨率屏幕适配方案,该方案适用于基于原生开发的Unity2D游戏 ...
- bzoj 4464: [Jsoi2013]旅行时的困惑【贪心】
据说正解是有上下界最小流,但是这种1e5的玩意问什么要跑网络流啊-- 贪心即可,注意一点是可以有多条路径经过一条边-- 以1为根,设d[u][0/1]为u到父亲的边是向下/向上,g记录这个点儿子中不能 ...
- 2014-7-7 NOIP模拟赛(图论)
1.无线通讯网(wireless.pas/cpp/c) [题目描述] 国防部计划用无线网络连接若干个边防哨所.2种不同的通讯技术用来搭建无线网络:每个边防哨所都要配备无线电收发器:有一些哨所还可以增配 ...
- css 的继承性
目录 css 的继承性是什么? 父元素的属性那些可以被子元素继承,哪些不能呢? css 的继承性是什么? 在面向对象语言都会存在继承的概念,在面向对象语言中,继承的特点:继承了父类的属性和方法. 那么 ...
- C#求圆的周长、面积、体积
窗体应用程序 private void button1_Click(object sender, EventArgs e) { double r; r = Convert.ToInt32(textBo ...