ios8 新的AlertView

2023-05-16

转自cocoachina

OS 8的新特性之一就是让接口更有适应性、更灵活,因此许多视图控制器的实现方式发生了巨大的变化。全新的UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸变化效果(比如说旋转)中发挥了重要的作用,它有效地节省了程序员们的工作量(天地良心啊)。还有,某些旧的UIKit控件也同样发生了许多变化,比如说Alert Views、Action Sheets、Popovers以及Search Bar Controllers。本文将会对Alert Views和Action Sheets发生的改变进行一个大致的介绍,我们会采用Objective-C和swift两种语言同时进行代码说明。

UIAlertView

随着苹果上次iOS 5的发布,对话框视图样式出现在了我们面前,直到现在它都没有发生过很大的变化。下面的代码片段展示了如何初始化和显示一个带有“取消”和“好的”按钮的对话框视图。

Objective-C版本:

1
2
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:@ "标题"  message:@ "这个是UIAlertView的默认样式"  delegate:self cancelButtonTitle:@ "取消"  otherButtonTitles:@ "好的" , nil];
[alertview show];

01.png

UIAlertView的默认样式

swift版本和Objective-C版本不同,在swift中,alertView的初始化只允许创建拥有一个取消按钮的对话框视图。或许您可以看到带有otherButtonTitles的init方法,但是很遗憾,这个方法是没有办法通过编译的。

1
2
var  alertView = UIAlertView(title:  "标题" , message:  "这个是UIAlertView的默认样式" , delegate: self, cancelButtonTitle:  "取消" )
alertView.show()

02.png

swift版本的UIAlertView

要能够创建和上面Objective-C版本相同的对话框视图,我们可以采取曲线救国的方法,虽然麻烦了些,但是我们为了目的可以不择手段的,是吧?

1
2
3
4
5
6
7
var  alertView = UIAlertView()
alertView.delegate = self
alertView.title =  "标题"
alertView.message =  "这个是UIAlertView的默认样式"
alertView.addButtonWithTitle( "取消" )
alertView.addButtonWithTitle( "好的" )
alertView.show()

您也可以通过更改UIAlertView的alertViewStyle属性来实现输入文字、密码甚至登录框的效果。

03.png

UIAlertView文本对话框

04.png

UIAlertView密码对话框

05.png

UIAlertView登录对话框

UIAlertViewDelegate协议拥有响应对话框视图的按钮动作的回调方法。还有当文本框内容改变时,调用alertViewShouldEnableOtherButton:方法可以让按钮动态地可用或者不可用。

要说明一点,苹果官方现在并不提倡在iOS 8中使用UIAlertView,取而代之的是UIAlertController。下面我们就来介绍UIAlertController的使用方法。

UIAlertController

在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一种模块化替换的方式来代替这两货的功能和作用。是使用对话框(alert)还是使用上拉菜单(action sheet),就取决于在创建控制器时,您是如何设置首选样式的。

一个简单的对话框例子

您可以比较一下两种不同的创建对话框的代码,创建基础UIAlertController的代码和创建UIAlertView的代码非常相似:

Objective-C版本:

1
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@ "标题"  message:@ "这个是UIAlertController的默认样式"  preferredStyle:UIAlertControllerStyleAlert];

swift版本:

1
var  alertController = UIAlertController(title:  "标题" , message:  "这个是UIAlertController的默认样式" , preferredStyle: UIAlertControllerStyle.Alert)

同创建UIAlertView相比,我们无需指定代理,也无需在初始化过程中指定按钮。不过要特别注意第三个参数,要确定您选择的是对话框样式还是上拉菜单样式。

通过创建UIAlertAction的实例,您可以将动作按钮添加到控制器上。UIAlertAction由标题字符串、样式以及当用户选中该动作时运行的代码块组成。通过UIAlertActionStyle,您可以选择如下三种动作样式:常规(default)、取消(cancel)以及警示(destruective)。为了实现原来我们在创建UIAlertView时创建的按钮效果,我们只需创建这两个动作按钮并将它们添加到控制器上即可。

Objective-C版本:

1
2
3
4
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@ "取消"  style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@ "好的"  style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];

swift版本:

1
2
3
4
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版本:

1
[self presentViewController:alertController animated:YES completion:nil];

swift版本:

1
self.presentViewController(alertController, animated:  true , completion: nil)

06.png

UIAlertController默认样式

按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,根据苹果官方制定的《iOS 用户界面指南》,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:

* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’

异常信息简洁明了,我们在此就不赘述了。

“警示”样式

什么是“警示”样式呢?我们先不着急回答这个问题,先来看一下下面关于“警示”样式的简单示例。在这个示例中,我们将前面的示例中的“好的”按钮替换为了“重置”按钮。

Objective-C版本:

1
2
UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@ "重置"  style:UIAlertActionStyleDestructive handler:nil];
[alertController addAction:resetAction];

swift版本:

1
2
var  resetAction = UIAlertAction(title:  "重置" , style: UIAlertActionStyle.Destructive, handler: nil)
alertController.addAction(resetAction)

07.png

“警示”样式

可以看出,我们新增的那个“重置”按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。

文本对话框

UIAlertController极大的灵活性意味着您不必拘泥于内置样式。以前我们只能在默认视图、文本框视图、密码框视图、登录和密码输入框视图中选择,现在我们可以向对话框中添加任意数目的UITextField对象,并且可以使用所有的UITextField特性。当您向对话框控制器中添加文本框时,您需要指定一个用来配置文本框的代码块。

举个栗子吧,要重新建立原来的登录和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,最后将密码输入框设置使用安全文本输入。

Objective-C版本:

1
2
3
4
5
6
7
8
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@ "文本对话框"  message:@ "登录和密码对话框示例"  preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
     textField.placeholder = @ "登录" ;
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
     textField.placeholder = @ "密码" ;
     textField.secureTextEntry = YES;
}];

swift版本:

1
2
3
4
5
6
7
8
9
alertController.addTextFieldWithConfigurationHandler { 
(textField: UITextField!) -> Void  in
     textField.placeholder =  "登录"
}
alertController.addTextFieldWithConfigurationHandler { 
(textField: UITextField!) -> Void  in
     textField.placeholder =  "密码"
     textField.secureTextEntry =  true
}

在“好的”按钮按下时,我们让程序读取文本框中的值。

Objective-C版本:

1
2
3
4
5
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) {
(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版本:

1
2
3
4
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
     ...
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification object:textField];
}];

swift版本:

1
2
3
4
5
alertController.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void  in
     ...
     NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector( "alertTextFieldDidChange:" ), name: UITextFieldTextDidChangeNotification, object: textField)
}

当视图控制器释放的时候我们需要移除这个Observer,我们通过在每个按钮动作的handler代码块(还有其他任何可能释放视图控制器的地方)中添加合适的代码来实现它。比如说在okAction这个按钮动作中:

Objective-C版本:

1
2
3
4
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@ "好的"  style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
     ...
     [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
}];

swift版本:

1
2
3
4
5
var  okAction = UIAlertAction(title:  "好的" , style: UIAlertActionStyle.Default) {
(action: UIAlertAction!) -> Void  in
     ...
     NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
}

在显示对话框之前,我们要冻结“好的”按钮

Objective-C版本:

1
okAction.enabled = NO;

swift版本:

1
okAction.enabled =  false

接下来,在通知观察者(notification observer)中,我们需要在激活按钮状态前检查“登录”文本框的内容。

Objective-C版本:

1
2
3
4
5
6
7
8
- (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版本:

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
         okAction.enabled = countElements(login.text) > 2
     }
}

08.png

UIAlertController的登录和密码对话框示例

好了,现在对话框的“好的”按钮被冻结了,除非在“登录”文本框中输入3个以上的字符:

上拉菜单

当需要给用户展示一系列选择的时候(选择恐惧症患者杀手),上拉菜单就能够派上大用场了。和对话框不同,上拉菜单的展示形式和设备大小有关。在iPhone上(紧缩宽度),上拉菜单从屏幕底部升起。在iPad上(常规宽度),上拉菜单以弹出框的形式展现。

创建上拉菜单的方式和创建对话框的方式非常类似,唯一的区别是它们的形式。

Objective-C版本:

1
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@ "保存或删除数据"  message:@ "删除数据将不可恢复"  preferredStyle: UIAlertControllerStyleActionSheet];

swift版本:

1
var  alertController = UIAlertController(title:  "保存或删除数据" , message:  "删除数据将不可恢复" , preferredStyle: UIAlertControllerStyle.ActionSheet)

添加按钮动作的方式和对话框相同。

Objective-C版本:

1
2
3
4
5
6
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];

swift版本:

1
2
3
4
5
6
var  cancelAction = UIAlertAction(title:  "取消" , style: UIAlertActionStyle.Cancel, handler: nil)
var  deleteAction = UIAlertAction(title:  "删除" , style: UIAlertActionStyle.Destructive, handler: nil)
var  archiveAction = UIAlertAction(title:  "保存" , style: UIAlertActionStyle.Default, 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或者其他紧缩宽度的设备上展示了,不出我们所料,运行得很成功。

Objective-C版本:

1
[self presentViewController:alertController animated:YES completion:nil];

swift版本:

1
self.presentViewController(alertController, animated:  true , completion: nil)

09.png

iPhone上的上拉菜单效果

如果上拉菜单中有“取消”按钮的话,那么它永远都会出现在菜单的底部,不管添加的次序是如何(就是这么任性)。其他的按钮将会按照添加的次序从上往下依次显示。《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来触发上拉菜单的,因此我们就将其作为描点。

在iOS 8中我们不再需要小心翼翼地计算出弹出框的大小,UIAlertController将会根据设备大小自适应弹出框的大小。并且在iPhone或者紧缩宽度的设备中它将会返回nil值。配置该弹出框的代码如下:

Objective-C版本:

1
2
3
4
5
6
UIPopoverPresentationController *popover = alertController.popoverPresentationController;
if  (popover){
     popover.sourceView = sender;
     popover.sourceRect = sender.bounds;
     popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
}

swift版本:

1
2
3
4
5
6
var  popover = alertController.popoverPresentationController
if  (popover != nil){
     popover?.sourceView = sender
     popover?.sourceRect = sender.bounds
     popover?.permittedArrowDirections = UIPopoverArrowDirection.Any
}

10.png

iPad上的上拉菜单效果

UIPopoverPresentationController类同样也是在iOS 8中新出现的类,用来替换UIPopoverController的。这个时候上拉菜单是以一个固定在源按钮上的弹出框的形式显示的。

要注意UIAlertController在使用弹出框的时候自动移除了取消按钮。用户通过点击弹出框的外围部分来实现取消操作,因此取消按钮便不再必需。

释放对话框控制器

通常情况下,当用户选中一个动作后对话框控制器将会自行释放。不过您仍然可以在需要的时候以编程方式释放它,就像释放其他视图控制器一样。您应当在应用程序转至后台运行时移除对话框或者上拉菜单。假定我们正在监听UIApplicationDidEnterBackgroundNotification通知消息,我们可以在observer中释放任何显示出来的视图控制器。(参考在viewDidLoad方法中设立observer的示例代码)。

Objective-C版本:

1
2
3
4
5
- (void)didEnterBackground:(NSNotification *)notification
{
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
   [self.presentedViewController dismissViewControllerAnimated:NO completion:nil];
}

swift版本:

1
2
3
4
func didEnterackground(notification: NSNotification){
     NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
     self.presentedViewController?.dismissViewControllerAnimated( false , completion: nil)
}

注意,要保证运行安全我们同样要确保移除所有的文本框observer。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ios8 新的AlertView 的相关文章

随机推荐

  • Opencv2.4.9源码分析——Stitching(三)

    3 相机参数评估 3 1 原理 相机参数的评估也称为相机定标 要想理解这部分内容 xff0c 首先应该从成像原理开始讲起 图6 小孔成像原理 从图6可以看出 xff0c 真实物体通过小孔映射到成像平面上 xff0c 小孔到成像平面的距离称为
  • computed 和 watch 的区别

    computed 注意data 里面不需要声明fullname lt template gt lt div class 61 34 hello 34 gt lt h1 gt fullName lt h1 gt lt div gt lt te
  • Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file

    Springboot2 3 4 RELEASE报错 xff0c 解决办法 升级jdk到11版本
  • excel 用一列数据生成图表/折线图

    问题描述 该教程适用于该列的长度很长 xff0c 数据量较大不适合鼠标拖动选中的情况 如果有更简单的方法也欢迎小伙伴们在评论区交流补充 操作步骤 1 点一下列上面的标号 即图中的B 2 按住ctrl xff0c 再点一下列的名称 即图中的a
  • ubuntu NVIDIA CC sanity check failed:

    ubuntu NVIDIA CC sanity check failed The C compiler does not appear to be able to create object files Please make sure y
  • Zeal -- 一款面向软件开发人员的离线文档浏览器

    简介 Zeal官网 就我而言 xff0c 经常忘记一些不常用的方法什么的 xff0c 难免需要查询API文档 xff0c 这时候有一个离线的文档浏览器还是很方便的 xff0c 可以集成多种语言文档 xff0c 便于查阅学习 对于 对于MAC
  • markdown-it 重定义渲染规则

    使用 markdown it 解析 markdown 代码 从这篇文章中了解到 markdown it 解析 markdown 代码的过程 xff0c 了解 token 和渲染规则 add target 61 34 blank 34 to
  • 马走日算法-回溯

    马走日算法 回溯 1 马走日走到目标节点最少的步数 include lt iostream gt include lt queue gt include lt functional gt include lt stack gt includ
  • MYSQL如何设置大小写敏感

    linux下mysql设置大小写不敏感 1 linux下mysql安装完后是默认 xff1a 区分表名的大小写 xff0c 不区分列名的大小写 xff1b 2 用root帐号登录后 xff0c 在 etc my cnf 中的 mysqld
  • Linux下几种图形化远程工具推荐

    好久没写文章了 xff0c 和大家聊聊最近在机器人调试中用到的几款远程桌面工具吧 在机器人调试过程中经常需要使用rviz之类的工具来查看机器人的运行状态 xff0c 图形化的远程工具必不可少 当然如果大家习惯用ssh或者没有图形化方面的需求
  • Win10x64-WDM设备驱动开发入门 - 第六章 VMware-Win10x64+WDK10+VS2015/2019环境搭建与双机调试

    VMware Win10x64 43 WDK10 43 VS2015 2019环境搭建与双机调试 1 驱动程序的开发语言选择调用约定运行时函数的调用 2 配置驱动开发环境1 vs2015 43 SDK 43 WDK10查看 win10 的版
  • 找出4*5矩阵中值最小和最大元素,并分别输出其值及所在的行号和列号 java

    package 矩阵 import java util Scanner public class 矩阵 public static void main String args TODO Auto generated method stub
  • 将python程序打包成exe可执行文件

    方法一 xff1a xff1a 打包完成后可以直接被他人使用 xff0c 他人不用安装python环境的 可以使用pyinstaller模块实现将python项目打包成exe执行文件 span class token triple quot
  • latex 如何在overleaf中插入算法伪代码

    问题描述 博主今天在用overleaf写论文 xff0c 急需插入伪代码 xff0c 将查阅结果记录在此以便后续参考 解决方案 overleaf有专门的说明文档来教大家如何正确插入伪代码 xff1a https www overleaf c
  • 手把手教你一整套R语言数据分析+建模流程

    手把手教你一整套R语言数据分析 43 建模流程 Intro项目背景前期准备数据描述数据清洗预分析及预处理数值型数据类别型数据 特征建模模型对比 Intro 近期在整理数据分析流程 xff0c 找到了之前写的一篇代码 xff0c 分享给大家
  • (工具技巧) —— Visual Studio Code页面放大缩小和字体的调整方式

    文章目录 Visual Studio Code页面放大缩小和字体的调整方式使用方式个人格言 Visual Studio Code页面放大缩小和字体的调整方式 使用方式 在日程的使用过程中 xff0c 有需要对Visual Studio Co
  • Centos7.8 安装 openldap+phpldapadmin 最详细步骤

    本文借助很多网上知识 做一个汇总 xff0c 并且自己手动一步步安装 很多openldap安装都是0几年的安装方式 xff0c 下面给大家演示我一步步安装的详细过程 xff0c CentOS7系统安装就不做演示了 xff0c 直接开肝 这里
  • Apache配置中文说明

    APACHE的配置 xff08 中文 xff09 基于 NCSA 服务的配置文件 这是Apache服务器主要配置文件 它包含服务器的影响服务器运行的配置指令 参见以取得关于这些指令的详细信息 不要只是简单的阅读这些指令信息而不去理解它 这里
  • ubunut 18.04安装xrdp及pulseaudio-module-xrdp

    1 桌面环境 sudo apt install xfce4 2 xrdp服务 sudo apt install xrdp 参考 xff1a xrdp 3 远程声音重定向 确认pulseaudio版本为11 1 pulseaudio vers
  • ios8 新的AlertView

    转自cocoachina OS 8的新特性之一就是让接口更有适应性 更灵活 xff0c 因此许多视图控制器的实现方式发生了巨大的变化 全新的UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸变化