iOS (封装)一句话调用系统的alertView和alertController
前言:
本文仅作参考存留,请用新版封装:iOS 更加优雅便捷的UIAlertView/UIAlertController封装使用
UIAlertController是iOS8.0之后出来的新方法,其将系统原先的UIAlertView和UIActionSheet进行了规范整合。iOS9.0之后,UIAlertView和UIActionSheet已经不建议使用,但还未彻底废弃。
alert提示窗可以算得上是十分常用的UI控件了,基于上述情况,考虑到版本兼容,笔者将上述控件进行了简单的整合封装。
封装之后,只需一句话,便可调用系统的alert提示,至于是调用alertView还是alertController,会根据系统版本自行判断,做到了兼容适配。alert提示窗的回调方法,也基于block进行了封装。按钮数量提供了变参和数组两种封装模式,各有用途。
代码见GitHub,已将这个较为简单但个人感觉还算十分实用的库进行了开源共享,喜欢的欢迎下载使用。
代码可能还入不了大牛的眼,水平有限,还望见谅,也欢迎使用和反馈。
支持的多种效果展示

下面叙述一下封装库内部分主要API的具体说明,代码中也有较为详细的注释。
1.普通alert 变参 兼容适配alertView和alertController
/**
* 普通alert定义 兼容适配alertView和alertController
*
* @param viewController 当前视图,alertController模态弹出的指针
* @param title 标题
* @param message 详细信息
* @param block 用于执行方法的回调block
* @param cancelBtnTitle 取消按钮,可为nil
* @param destructiveBtn alertController的特殊按钮类型,可为nil
* @param otherButtonTitles 其他按钮 变参量 但是按钮类型的相对位置是固定的,可为nil
* NS_REQUIRES_NIL_TERMINATION 是一个宏,用于编译时非nil结尾的检查 自动添加结尾的nil
***注意1***
//block方法序列号和按钮名称相同,按钮类型排列顺序固定
//如果取消为nil,则index0为特殊,以此往后类推,以第一个有效按钮为0开始累加
//取消有的话默认为0
***注意2***
destructiveButtonTitle
iOS8以前,alert设置无效,因为不支持
iOS8以后,alert设置有效
*/
+ (void) showAlertWith:(UIViewController *)viewController
title:(NSString *)title
message:(NSString *)message
callbackBlock:(CallBackBlock)block
cancelButtonTitle:(NSString *)cancelBtnTitle
destructiveButtonTitle:(NSString *)destructiveBtn
otherButtonTitles:(NSString *)otherButtonTitles, ...NS_REQUIRES_NIL_TERMINATION;
具体调用实例(默认系统是ios8以后的):
[JXTAlertTools showAlertWith:self title:EmptyTitle message:_titleArray[indexPath.row] callbackBlock:^(NSInteger btnIndex) {
if (btnIndex == 0) {
NSLog(@"取消");
}
if (btnIndex == 1) {//注意ios8以前,没有这个键
NSLog(@"特殊");
}
if (btnIndex == 2) {
NSLog(@"其他");
}
} cancelButtonTitle:@"取消" destructiveButtonTitle:@"特殊" otherButtonTitles:@"其他", nil];
没有按钮时:
//没有按钮时,默认自动消失
[JXTAlertTools showAlertWith:self title:EmptyTitle message:_titleArray[indexPath.row] callbackBlock:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil, nil];
弹窗自动消失的持续时间由宏控制,可自行修改(详见JXTAlertTools.h):
/**
* 弹框显示的时间,默认1秒
*/
#define AlertViewShowTime 1.0
2.多按钮数组模式排布alert 兼容适配alertView和alertController
/**
* 多按钮列表数组排布alert初始化 兼容适配
*
* @param viewController 当前视图,alertController模态弹出的指针
* @param title 标题
* @param message 详细信息
* @param block 用于执行方法的回调block
* @param cancelBtnTitle 取消按钮
* @param otherBtnTitleArray 其他按钮的标题数组
* @param otherBtnStyleArray 按钮样式分布数组(普通/特殊),alertView默认为普通样式
***注意***
UIAlertActionStyleCancel/JXTAlertActionStyleCancel最多只能有一个,否则崩溃
Log:
'UIAlertController can only have one action with a style of UIAlertActionStyleCancel'
*/
+ (void)showArrayAlertWith:(UIViewController *)viewController
title:(NSString *)title
message:(NSString *)message
callbackBlock:(CallBackBlock)block
cancelButtonTitle:(NSString *)cancelBtnTitle
otherButtonTitleArray:(NSArray *)otherBtnTitleArray
otherButtonStyleArray:(NSArray *)otherBtnStyleArray;
此方法是为了弥补前面那个方法初始化时,alert的按钮样式排布相对固定的局限,当然,这种排布只在iOS8之后有效。
具体调用实例(默认系统是ios8以后的):
NSArray * titles = @[@"确定1", @"特殊1", @"确定2", @"特殊2"];
NSArray * styles = @[
[NSNumber numberWithInteger:JXTAlertActionStyleDefault],
[NSNumber numberWithInteger:JXTAlertActionStyleDestructive],
[NSNumber numberWithInteger:JXTAlertActionStyleDefault],
[NSNumber numberWithInteger:JXTAlertActionStyleDestructive]
];
[JXTAlertTools showArrayAlertWith:self title:EmptyTitle message:_titleArray[indexPath.row] callbackBlock:^(NSInteger btnIndex) {
if (btnIndex == 0) {
NSLog(@"取消");
}
else
NSLog(@"%@", titles[btnIndex - 1]);
} cancelButtonTitle:@"取消" otherButtonTitleArray:titles otherButtonStyleArray:styles];
上面要注意按钮的样式是枚举值,添加数组时要注意转化为对象,这里用了NSNumber,因为方法实现中也是按照NSNumber解析的:
NSNumber * styleNum = otherBtnStyleArray[i];
UIAlertActionStyle actionStyle = styleNum.integerValue;
UIAlertAction *otherAction = [UIAlertAction actionWithTitle:otherBtnTitleArray[i] style:actionStyle handler:^(UIAlertAction *action) {
block(count);
}];
[alertController addAction:otherAction];
样式枚举定义:
typedef enum {
JXTAlertActionStyleDefault = 0,
JXTAlertActionStyleCancel,
JXTAlertActionStyleDestructive
}JXTAlertActionStyle;
这里之所以不用系统提供的:
typedef NS_ENUM(NSInteger, UIAlertActionStyle) {
UIAlertActionStyleDefault = 0,
UIAlertActionStyleCancel,
UIAlertActionStyleDestructive
} NS_ENUM_AVAILABLE_IOS(8_0);
是因为为了系统版本适配,系统的样式枚举是iOS8之后才提供的,如果直接使用,系统版本一旦低于iOS8,此时使用可能导致程序崩溃。
没有按钮时,情况同上:
[JXTAlertTools showArrayAlertWith:self title:EmptyTitle message:_titleArray[indexPath.row] callbackBlock:nil cancelButtonTitle:nil otherButtonTitleArray:nil otherButtonStyleArray:nil];
关于actionSheet的API,基本同上,也提供了两个相应的方法,同样是兼容适配的。
关于方法的具体实现,在此不再赘述,有兴趣的可以参考代码,有什么问题欢迎讨论。
3.两种简易提示窗
这两种建议的提示窗,是基于上述方法的简化,适用于较为简单的提示场景。
1.单按钮或无按钮alert提示
[JXTAlertTools showTipAlertViewWith:self title:EmptyTitle message:_titleArray[indexPath.row] buttonTitle:@"确认" buttonStyle:JXTAlertActionStyleDefault];
2.窗口底部简易actionSheet,无按钮
[JXTAlertTools showBottomTipViewWith:self title:_titleArray[indexPath.row] message:_titleArray[indexPath.row]];
4.两个特殊用途的方法
- 1.判断当前窗口是否有alert/actionSheet显示
+ (BOOL)isAlertShowNow;
这个的用途具体看需求,可以用来去重显示,尤其是在alertView的情况下,有时可能连续多次弹出同一alertView,例如观察者回调,系统貌似没有做去重处理,笔者就遇到过监听回调导致的alert重复显示。但是如果是alertController,就不会发生了,控制台可能会直接给出警告的,因为是试图在一个已经销毁的vc上(第一次弹出的alertController消失时)第二次连续推出视图,这是做不到的。
做去重显示判定时,此方法慎用,因为未做弹窗区分,同时的弹窗有可能是因为重复显示,也可能是不同警告类型的提示窗,去重的话就可能导致第二个不同的提示窗被过滤掉。
用法示例:
NSLog(@"显示alert:%@", [JXTAlertTools isAlertShowNow] ? @"是" : @"否");
if (![JXTAlertTools isAlertShowNow]) {//检测弹窗,控制alertView的去重显示
[JXTAlertTools showTipAlertViewWith:self title:EmptyTitle message:_titleArray[indexPath.row] buttonTitle:nil buttonStyle:JXTAlertActionStyleDefault];
}
NSLog(@"显示alert:%@", [JXTAlertTools isAlertShowNow] ? @"是" : @"否");
控制台输出:

可能用方法有问题,但我是临时这个解决的。。。
- 2.查找当前活动窗口
+ (UIViewController *)activityViewController;
这个方法源于网络,实际使用可行,主要是用来确定alertController的,也就是上面那个方法有用到此方法(已封装),当然这个方法不局限于只确定alertController。而且,alertView的检测和alertController的检测不是同一个方法,毕竟一个是view,一个是vc。
5.封装时遇到的一个小问题
当且仅当模拟器使用6p或者6sp时,alert有至多2个按钮,至少1个按钮,alert的message中使用“\n”时,分为3行,第一行无所谓,第2行字符小于38字符或者第3行字符小于76时(\n算一个字符,数字可能记错了。。。),控制台直接给了下面的警告,警告的达成条件较为苛刻,2、3任意一行多于临界值都不行,但的确是偶然,同样的字符数,没有“\n”就没事,多于这几个临界值也没事,唯独不能少。。。:
最简单的一个messge实例:@“1\n2\n3”
警告:
2016-01-28 10:13:47.714 JXTAlertTools[2379:60409] the behavior of the UICollectionViewFlowLayout is not defined because:
2016-01-28
10:13:47.715 JXTAlertTools[2379:60409] the item height must be less
than the height of the UICollectionView minus the section insets top and
bottom values, minus the content insets top and bottom values.
2016-01-28
10:13:47.715 JXTAlertTools[2379:60409] The relevant
UICollectionViewFlowLayout instance is
<_UIAlertControllerCollectionViewFlowLayout: 0x7fc21ac7ed10>, and
it is attached to <UICollectionView: 0x7fc21c877a00; frame = (0
94.6667; 270 44); clipsToBounds = YES; gestureRecognizers = <NSArray:
0x7fc21ac1b5d0>; layer = <CALayer: 0x7fc21ac1c470>;
contentOffset: {0, 0}; contentSize: {0, 0}> collection view layout:
<_UIAlertControllerCollectionViewFlowLayout: 0x7fc21ac7ed10>.
2016-01-28
10:13:47.715 JXTAlertTools[2379:60409] Make a symbolic breakpoint at
UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the
debugger.
不是无聊,只是偶然碰到这个情况,当时还排查了半天,最后才发现是这个问题,这也是很容易遇到的问题,无论是alertView还是alertController,都会出现。
复制代码:
UIAlertView * al = [[UIAlertView alloc] initWithTitle:@"title" message:@"1\n2\n2" delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
[al show];
或者:
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"title" message:@"1\n2\n2" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * act =[UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"输出");
}];
[alert addAction:act];
[self presentViewController:alert animated:YES completion:nil];
用6p或者6sp运行,就会出现上述警告,原因不明(系统bug?)。。。其他模拟器都没事。这里提出来只是提醒注意规避吧。
而且分析上述警告也很有意思,大致是说UICollectionView的布局有问题,这是不是可以说明系统的alertView或者alertController都是利用UICollectionView进行封装的呢?
上述临界情况的样式:
1.不会出现的:

2.会出现的,仅仅是少了一个字符:

参考文章:
1.iOS 引用当前显示的UIAlertView
2.IOS -获取当前视图的Controller
3.UIWindowLevel详解
·转载请声明出处·
iOS (封装)一句话调用系统的alertView和alertController的更多相关文章
- iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话,iTunes,iBooks )
在网上找到了下在记录下来以后方便用 在程序中调用系统自带的应用,比如我进入程序的时候,希望直接调用safar来打开一个网页,下面是一个简单的使用:
- iOS开发之调用系统打电话发短信接口以及程序内发短信
在本篇博客开头呢,先说一下写本篇的博客的原因吧.目前在做一个小项目,要用到在本应用程序内发验证码给其他用户,怎么在应用内发送短信的具体细节想不大起来了,于是就百度了一下,发现也有关于这方面的博客,点进 ...
- ios开发之 -- 调用系统定位获取当前经纬度与地理信息
ios 10定位: 在info.plist中加入: //允许在前台使用时获取GPS的描述 定位权限:Privacy - Location When In Use Usage Description / ...
- ios开发之 --调用系统的页面,显示中文
在开发的过程中,我们会接入很多的sdk,比如相机,相册,是否允许获取位置等,大多数的情况下是默认显示英文, 在plist文件里面添加一个key就可以了,如下图: key:Localization na ...
- ios调用系统相册、相机 显示中文标题、本地化多语言支持
因为调用系统相册.相机需要显示中文,所以搞了半天才知道是在Project->info->Custom ios Target Properties 添加 Localizations 并加入C ...
- IOS中调用系统的电话、短信、邮件、浏览功能
iOS开发系列--通讯录.蓝牙.内购.GameCenter.iCloud.Passbook系统服务开发汇总 2015-01-13 09:16 by KenshinCui, 26990 阅读, 35 评 ...
- iOS调用系统通讯录获取姓名电话号码(转)
原文地址:http://blog.csdn.net/idoshi201109/article/details/46007125 OS调用系统通讯录获取姓名电话号码 (iOS 8.0 Xcode6.3可 ...
- iOS中 读取相册,调用系统相机 技术分享
技术内容:分别读取相册以及调取相机,将图片显示到imageView上 布局: 1.创建imageView 和 button 并为button一个关联pickerImage的事件 <div sty ...
- ios 调用系统应用的方法 应用间跳转的方法
声明一个私有方法: #pragma mark - 私有方法 -(void)openUrl:(NSString *)urlStr{ //注意url中包含协议名称,iOS根据协议确定调用哪个应用,例如发送 ...
随机推荐
- hdu(2846)Repository
Problem Description When you go shopping, you can search in repository for avalible merchandises by ...
- unity坐标转换问题
unity最经常使用的几种坐标.屏幕坐标.世界坐标.ngui坐标,相对于父物体的坐标(localPoisition). 可是有时候这几种坐标相互转换何其困难,让自己狠抓头. 不得不操作的方式是创建虚拟 ...
- CountDownTimer,0,0
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); s ...
- 0x04 二分
二分.三分其实没什么.. 但是真心觉得市面上的朴素二分打法千奇百怪,假如是像我的标程应该是比较稳妥的,然而poj2018那题(前缀和又想起来了)是向下取整,精度有点问题(经常拍出一些什么xxx.999 ...
- spark Bisecting k-means(二分K均值算法)
Bisecting k-means(二分K均值算法) 二分k均值(bisecting k-means)是一种层次聚类方法,算法的主要思想是:首先将所有点作为一个簇,然后将该簇一分为二.之后选择能最大程 ...
- 29.QT主窗口加widget
运行效果 widget布局showwidget.h #ifndef SHOWWIDGET_H #define SHOWWIDGET_H #include <QWidget> #includ ...
- 下压栈(LIFO)详解
写在前面的话: 一枚自学Java和算法的工科妹子. 算法学习书目:算法(第四版) Robert Sedgewick 算法视频教程:Coursera Algorithms Part1&2 本文 ...
- 清北集训Day1T3 LYK loves jumping(期望DP)
题目描述 LYK在玩一个魔法游戏,叫做跳跃魔法. 有n个点,每个点有两个属性hi和ti,表示初始高度,和下降高度.也就是说,它初始时高度为hi,一旦LYK踩在这个点上,由于重力的影响,这个点的高度会下 ...
- iOSUI显示思想
两级显示机制: 1.cpu: 2.GPU: 和操作系统的多级缓存机制有点类似.
- C++的头文件(转)
这几天在写比较困难的一部分,所以也没有时间总结一些东西了,不过昨天翻我的笔记本,发现了一篇还不错的笔记,给大家看看. C/C++头文件一览 C.传统 C++ #include <assert.h ...