UIAlertController的用法解析

iOS 8的新特性之一就是让接口更有适应性、更灵活,因此许多视图控制器的实现方式发生了巨大的变化,并且在某些旧的UIKit控件也同样发生了许多变化,往统一的方向发展,比如说Alert Views、Action Sheets、Popovers以及Search Bar Controllers。这里将会对Alert Views和Action Sheets发生的改变进行一个大致的介绍.

UIAlertView

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

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"我是标题" message:@"我是传递的消息正文" delegate:self cancelButtonTitle:@"取消按钮" otherButtonTitles:@"确定按钮", nil];
    [alertView show];

展示效果

UIAlertView的默认样式.png

并且通过一系列的代理方法来处理按钮点击的事件


alertView代理方法.png

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

typedef NS_ENUM(NSInteger, UIAlertViewStyle) {
    UIAlertViewStyleDefault = 0, //默认效果
    UIAlertViewStyleSecureTextInput,//单行密文文本输入框
    UIAlertViewStylePlainTextInput,//单行普通文本输入框
    UIAlertViewStyleLoginAndPasswordInput//登录输入框
}

单行输入框效果

   alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
单行文本框.png

单行secure entry

alertView.alertViewStyle = UIAlertViewStyleSecureTextInput;
单行密文文本输入框.png

双行登录框效果

alertView.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
双行登录框效果.png

通过

- (nullable UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex ;

这个方法可以拿到在index位置的文本输入框. 从而监听文本输入框的改变

    [alertView textFieldAtIndex:0];
    [alertView textFieldAtIndex:1];

UIActionSheet

展示效果是从屏幕的底部往上钻出1个可点击的表格,对于这个控件的使用与UIAlertView 基本类似

  UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"我是标题" delegate:self cancelButtonTitle:@"取消按钮" destructiveButtonTitle:@"确定按钮" otherButtonTitles:@"关闭", nil];
    [sheet showInView:self.view];
UIActionSheet.png

也有一系列的代理方法来处理点击按钮事件

    - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex;
    - (void)actionSheetCancel:(UIActionSheet *)actionSheet;
    - (void)willPresentActionSheet:(UIActionSheet *)actionSheet ;
    - (void)didPresentActionSheet:(UIActionSheet *)actionSheet;
    - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex;
    - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex;

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

UIAlertController

UIAlertController以一种模块化替换的方式来代替上面两个控件的功能和作用。是使用弹出对话框(alert)还是使用向上钻出的菜单(action sheet),就取决于在创建控制器时,是如何设置首选样式的。

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"我是标题" message:@"我是要传递的消息" preferredStyle:UIAlertControllerStyleActionSheet];

preferredStyle的枚举,通过指定样式来确定是以什么方法展示

    typedef NS_ENUM(NSInteger, UIAlertControllerStyle) {
        UIAlertControllerStyleActionSheet = 0,
        UIAlertControllerStyleAlert
    }

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

由于创建出来的AlertController 变成了1个控制器 所以要使用modal的方式将控制器展示出来

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

如果仅仅是上面的两句代码 同创建UIAlertView相比,我们没有指定代理,也没有在初始化过程中指定按钮。那么控制器弹出后 没有任何按钮和文本输入框. 不过要特别注意第三个参数,要确定选择的是对话框样式还是向上钻的菜单样式


alert.png

actionSheet.png

接下来要往alertController中添加按钮或者文本输入框,通过创建UIAlertAction的实例,可以将动作按钮添加到控制器上。UIAlertAction由标题字符串、样式以及当用户选中该动作时运行的代码块组成。通过UIAlertActionStyle,您可以选择如下三种动作样式:常规(default)、取消(cancel)以及破坏性的,警示效果(destruective)[点击这个按钮一般要造成改变,所以按钮的样式系统默认会变为红色]。为了实现原来我们在创建UIAlertView时创建的按钮效果,我们只需创建两个动作按钮并将它们添加到控制器上即可。

按钮

typedef NS_ENUM(NSInteger, UIAlertActionStyle) {
    UIAlertActionStyleDefault = 0,//默认
    UIAlertActionStyleCancel,//取消  唯一
    UIAlertActionStyleDestructive//破坏性,警示效果按钮文字变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。
}
    UIAlertAction *CancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    
    UIAlertAction *action2 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        
    }];

样式如下


alertController.png

按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
Terminating app due to uncaught exception
‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’

文本对话框

UIAlertController极大的灵活性意味着您不必拘泥于内置样式。以前我们只能在默认视图、文本框视图、密码框视图、登录和密码输入框视图中选择,现在我们可以向对话框中添加任意数目的UITextField对象,并且可以使用所有的UITextField特性。当您向对话框控制器中添加文本框时,您需要指定一个用来配置文本框的代码块
要重新建立原来的登录和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,最后将密码输入框设置使用安全文本输入。例如

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"我是标题" message:@"我是要传递的消息" preferredStyle:UIAlertControllerStyleActionSheet];
//取消按钮
UIAlertAction *CancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    }];
//警示按钮
UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
    }];
//文本输入框
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        //配置文本框的代码块
        textField.placeholder = @"登录";
        textField.textColor = [UIColor greenColor];
    }];
    
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"密码";
        textField.secureTextEntry = YES;
    }];
    
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"打酱油的";
    }];
[alertController addAction:CancelAction];
[alertController addAction:doneAction];
[self presentViewController:alertController animated:YES completion:nil];

上面的例子添加了三个文本输入框 那么显示的效果就会变成这样


展示效果.png

但是如果试图向样式为actionSheet的alertController添加输入框,将会抛出异常:
Terminating app due to uncaught exception:
NSInternalInconsistencyException, reason: 'Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert'

在很多情况下 当我们点击确定按钮之后希望拿到文本框的值然后做一些事情.那么我们可以这样来操作
在 doneAction 创建的时候在代码块里面添加下面的代码 当点击确定按钮的时候 在控制台就会打印 在textField输入的值

UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"%@--%@",alertController.textFields.firstObject.text,alertController.textFields.lastObject.text);
    }];

要注意的是,以上的写法是有问题的..由于在创建 doneAction 的时候 在block 里面 引用了 alertController 之后再将doneAction 添加到 alertController 里面. 那么将会产生循环引用导致alertController无法销毁.
所以此时应该这样做

   UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"我是标题" message:@"我是要传递的消息" preferredStyle:UIAlertControllerStyleAlert];
//避免产生循环引用问题
    __weak typeof(alertController) weakAlert = alertController;
    UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        NSLog(@"%@--%@",weakAlert.textFields.firstObject.text,weakAlert.textFields.lastObject.text);
    }];
  ........................
 [alertController addAction:doneAction];
 [self presentViewController:alertController animated:YES completion:nil];

如果需要监听文本输入框输入的改变.可以使用两种方式

  • 1 使用通知(需要在alertView 销毁的时候 ,移除通知 ,即在每个按钮动作的handler代码块中添加合适的代码来移除).
doneAction.enabled = NO;
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"登录";
        textField.textColor = [UIColor greenColor];
        //注册通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accountTextFieldChange:) name:UITextFieldTextDidChangeNotification object:textField];
    }];
 - (void)accountTextFieldChange:(NSNotification *)notification{
//在这里拿到文本框
}

//移除通知

  __weak typeof(alertController) weakAlert = alertController;
    UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        
        NSLog(@"%@--%@",weakAlert.textFields.firstObject.text,weakAlert.textFields.lastObject.text);
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
    }];

  • 2 使用addTarget(推荐使用这种方式.)
    举个栗子:当文本输入框里面的内容长度>3的时候才让确定按钮能够点击.
    首先要冻结 doneAction 按钮
doneAction.enabled = NO;
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.placeholder = @"登录";
        textField.textColor = [UIColor greenColor];
 [textField addTarget:self action:@selector(accountTextFieldChange:) forControlEvents:UIControlEventEditingChanged];
- (void)accountTextFieldChange:(UITextField *)accountTextFiled{
    //获取alertController
    UIAlertController *alertController = (UIAlertController *)self.presentedViewController;
    //拿到doneAction按钮
    UIAlertAction * doneAction = alertController.actions[1];
//判断语句
    if (accountTextFiled.text.length >= 3) {
        doneAction.enabled = YES;
    }
确定按钮不可用.png
确定按钮可用.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容