防止多个UIAlertView重叠弹出
http://www.jianshu.com/p/7ac398ef4532
项目中可能会遇到这种情况,好几个alertView因为逻辑关系全部弹出,用户需要一个个的点击才能将所有的alertView取消掉。或者说这种情况下,我们只需要弹出一个alertView就OK了。
alertView是怎么弹出的?网上查找资料说是,每次执行[alertView show],这个方法的时候是新建了一个window,将alertView显示在了window上面。代码验证的确是这样的。
代码验证alertView是添加到哪里的。
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    tempBtn.frame = CGRectMake(100, 100, 100, 100);
    tempBtn.backgroundColor = [UIColor cyanColor];
    [tempBtn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:tempBtn];
}
- (void)clickBtn:(UIButton *)sender
{
    UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"title1" message:@"message1" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [alert1 show];
 NSLog(@"alert1.window = %@   alert1.window.windowLevel = %f",alert1.window,alert1.window.windowLevel);
    NSLog(@"app.window = %@",app.window);
    NSLog(@"windows == %@",[UIApplication sharedApplication].windows);
}测试结果:
alert1.window = <_UIAlertControllerShimPresenterWindow: 0x7f9ee8c07940; frame = (0 0; 414 736); opaque = NO; gestureRecognizers = <NSArray: 0x618000056aa0>; layer = <UIWindowLayer: 0x6180000240a0>>   alert1.window.windowLevel = 2001.000000
app.window = <UIWindow: 0x7f9ee8f03f80; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x608000052f60>; layer = <UIWindowLayer: 0x608000022100>>
 windows == (
    "<UIWindow: 0x7f9ee8f03f80; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x608000052f60>; layer = <UIWindowLayer: 0x608000022100>>"
)通过打印的结果可以看出:
1、alert1.window没有在[UIApplication sharedApplication].windows中出现window和windows的关系参考:http://www.jianshu.com/p/75befce85623,windows中只有app.window也就是当前的最底层的控件。
2、alert1.window的windowLevel是2001比app.window的大,APP.window的windowLevel是0,所以alertView显示在了app.window的上面。相关windowLevel的问题参考:http://www.jianshu.com/p/f60471a7d935
搞懂了alertView显示的大致原理了,那么往我们的需求上靠
- (void)clickBtn:(UIButton *)sender
{
    UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"title1" message:@"message1" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [alert1 show];
    UIAlertView *alert2 = [[UIAlertView alloc] initWithTitle:@"title2" message:@"message2" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [alert2 show];
//    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
//
//    NSLog(@"alert1.window = %@   alert1.window.windowLevel = %f",alert1.window,alert1.window.windowLevel);
//    NSLog(@"app.window = %@",app.window);
//    NSLog(@"windows == %@",[UIApplication sharedApplication].windows);
}想要多余的alertView不显示,两种方法:
1、要么让他不展示
2、要么让他展示了自己再消失
第一种我感觉做不到,显示的逻辑是写死的。
那就拿第二种下手,前提是怎么获取到已经展示的alertView?
上面介绍的alertView显示,是显示在系统给自己创建的Window上面的,但是这个window还获取不到。那怎么办。
有这么一种思路,将所有显示的alertView记录在自己的一个数组中,然后不就想干嘛就干嘛了嘛!!关键点是记录的时机,这里选取show方法执行的时候
思路1:
使用runtime方法检测show方法,然后在执行show方法的时候记录alertView,相关代码如下:
创建记录alertView的单例
#import <Foundation/Foundation.h>
@interface AlertViewRecorder : NSObject
@property (nonatomic, strong)NSMutableArray * alertViewArray;
+ (AlertViewRecorder *)shareAlertViewRecorder;
@end#import "AlertViewRecorder.h"
@implementation AlertViewRecorder
// 创建单例,记录alertView
+ (AlertViewRecorder *)shareAlertViewRecorder
{
    static AlertViewRecorder *recoder = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(recoder == nil){
            recoder = [[AlertViewRecorder alloc] init];
        }
    });
    return recoder;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.alertViewArray = [[NSMutableArray alloc] init];
    }
    return self;
}
@end关键代码
#import "UIAlertView+MyAlertView.h"
#import <objc/message.h>
#import "AppDelegate.h"
#import "AlertViewRecorder.h"
@implementation UIAlertView (MyAlertView)
+ (void)load
{
    // 获取将要交换的两个方法
    Method showMethod = class_getInstanceMethod(self, @selector(show));
    Method myShowMethod = class_getInstanceMethod(self, @selector(myShow));
    // 将两个方法互换
    method_exchangeImplementations(showMethod, myShowMethod);
}
- (void)myShow
{
    // 将之前所有的alertView取出来消失掉
    NSMutableArray *array =  [AlertViewRecorder shareAlertViewRecorder].alertViewArray;
    for (UIAlertView *alertView in array) {
        if ([alertView isKindOfClass:[UIAlertView class]]) {
            [alertView dismissWithClickedButtonIndex:-1 animated:YES];
        }
    }
    [array removeAllObjects];
    // 调用自身的方法
    [self myShow];
    [array addObject:self];
}
@end测试代码可行;
思路2:
创建分类,重写show方法,在重写的show方法中调用show方法的同时,记录alertView到相关数组,和思路1差不多。
思路1相对于思路2的优点,个人认为,当项目开发了一段时间或者半路接手项目的时候,思路1更有优势。
如有失误请各位路过大神即时指点,或有更好的做法,也请指点一二,在下感激不尽。
代码连接:https://github.com/RunOfTheSnail/MyAlertViewDemo
原文链接:http://www.jianshu.com/p/7ac398ef4532
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
防止多个UIAlertView重叠弹出的更多相关文章
- 自定义一个类似UIAlertView的弹出框
		这个是和UIAlertView类似,但是可以自定义view的样式废话不多说,上代码: 首先第一步:创建一个继承自View的类如: #import <UIKit/UIKit.h> @clas ... 
- UIAlertView弹出视图动画效果
		在App设计中为了加强用户体验,我们会常常加入一些友好的动画效果.比如类似UIAlertView弹出的动画效果,由于系统中并没有直接提供类似的动画API,如果我们想要做出一样的效果,那就得深入的研究一 ... 
- JQuery EasyUI dialog弹出框的 close 和 destroy
		开发项目中(使用JQuery EasyUI),根据业务需要重叠弹出多个提示框的情况,会出现如下情况:页面出现两个div模块调用同一个弹出页面,页面的数据接受框元素不能实时存储数据解决方案: 使用$(t ... 
- UIAlertView弹出框
		<Alert弹出框提示用户信息> 1.遵循代理方法<UIAlertViewDelete> 2.调用方法UIAlertView *alert = [[UIAlertV ... 
- 在没有界面的类中,实现弹出UIAlertView  ||  在没有界面的类中,刷新程序界面 思路
		+(DisplayErrorMsg *)sharedDisplayErrorMsg { static DisplayErrorMsg *instance = nil; @synchronized(in ... 
- iOS自定义提示弹出框(类似UIAlertView)
		菜鸟一枚,大神勿喷.自己在牛刀小试的时候,发现系统的UIAlertView有点不喜欢,然后就自己自定义了一个UIAlertView,基本上实现了系统的UIAlertView,可以根据项目的需求修改UI ... 
- 使Toast弹出不重叠的封装
		一.问题 在频繁弹出toast的时候,弹出后出现延迟重叠的现象. 二.解决 Toast通常由makeTextT()方法实例化,如何不想要toast弹出时重叠,那么只需在应用中保持一个Toast对象即可 ... 
- 阶段一:为View设置阴影和弹出动画(天气应用)
		“阶段一”是指我第一次系统地学习Android开发.这主要是对我的学习过程作个记录. 上一篇阶段一:通过网络请求,获得并解析JSON数据(天气应用)完成了应用的核心功能,接下来就要对它进行优化.今天我 ... 
- 【代码笔记】iOS-轮询弹出框
		一,效果图. 二,工程图. 三,代码. RootViewController.m #import "RootViewController.h" //加入弹出框的头文件 #impor ... 
随机推荐
- javaweb作業中的幾個要點
			1.DDoS攻击原理DDoS是指分布式拒绝服务(Distributed Denial of Service):试图通过恶意请求使系统或者网络超载进而无法继续提供服务.对于一个网站来说,这意味着,该网站 ... 
- Hibernate 系列教程14-继承-PerTable策略
			Employee public class Employee { private Long id; private String name; HourlyEmployee public class H ... 
- CodeForces 429B  Working out 动态规划
			Description Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to loo ... 
- 关于前台主键输入错误对后台hibernate方法的影响
			由于前台输入时开始不小心打错了主键为value=“${conf_id}”/ 导致后台得到的主键不是数字“1”而是“1/”所以到后台就算是进的updata方法结果运行的却是添加方法 原因可能是传入的对象 ... 
- [转]Android之Context和Activity互相转换
			1.context转换为activity Activity activity = (Activity) context; 2.从activity得到context 在activity的方法中用cont ... 
- aspx基础开始
			<%@ Page Language="C#" Debug="true" trace="false" validateRequest=& ... 
- boost之词法解析器spirit
			摘要:解析器就是编译原理中的语言的词法分析器,可以按照文法规则提取字符或者单词.功能:接受扫描器的输入,并根据语法规则对输入流进行匹配,匹配成功后执行语义动作,进行输入数据的处理. C++ 程序员需要 ... 
- 自定义solr的search UI
			solr使用apache的velocity来定义UI,在solr的search ui的基础上更改即可,主要改\example\solr\collection1\conf\velocity里的文件. 详 ... 
- 转 图片缓存之内存缓存技术LruCache,软引用
			每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一 ... 
- iOS开发-正则表达式3种形式
			转至:http://www.cnblogs.com/GarveyCalvin/p/4250145.html iOS开发-正则表达式的使用方法 前 言:在表单验证中,我们经常会使用到正则,因为我们需要用 ... 
