防止多个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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-10-05 22:02:32

防止多个UIAlertView重叠弹出的相关文章

UIAlertView弹出框

<Alert弹出框提示用户信息>    1.遵循代理方法<UIAlertViewDelete>    2.调用方法UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"恭喜通关!" message:@"更多精彩,请购买下一关~~" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"购买&

UIAlertView - 弹出框

UIAlertView 继承于UIView 初始化方法:- (id)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id /* <UIAlertViewDelegate>*/)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles,...,nil;  

bug报告:UIAlertView消失之后收起的键盘又弹出

iOS8之后,有了UIAlertController这个类,如下 NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertController : UIViewController 很明显,苹果强烈建议广大码农们如果能不用UIAlertView就不要用啦,因为我们有UIAlertController了! 进入正题... 为了兼容iOS7,我们的项目中就统一使用了UIAlertView.问题来了:(项目中的某一)界面中textField处于编辑状态(界面上有键盘

bug日志(1):UIAlertView消失之后收起的键盘又弹出

iOS8之后,有了UIAlertController这个类,如下 NS_CLASS_AVAILABLE_IOS(8_0) @interface UIAlertController : UIViewController 很明显,苹果强烈建议广大码农们如果能不用UIAlertView就不要用啦,因为我们有UIAlertController了! 进入正题...... 为了兼容iOS7,我们的项目中就统一使用了UIAlertView.问题来了:(项目中的某一)界面中textField处于编辑状态(界面上

关于UIAlertView弹出警告框自动消失

很多事时候弹出框只是为了提示用户,为了避免让用户过多不必要的操作,让弹出框自动消失就可以了 + (void)showDismissedAlertDialog:(NSString*)message { UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil   //NSLocalizedString(@"错误", nil) message:NSLocalizedString(message, nil) delegate:se

UIAlertView 弹出提示

UIAlertView *sussess = [[UIAlertView alloc]initWithTitle:nil message:@"发布成功" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil]; [sussess show]; 弹出单击确定 操作:delegate:self  遵守协议<UIAlertViewDelegate> -(void)alertView:(UIAle

iOS自定义提示弹出框(类似UIAlertView)

菜鸟一枚,大神勿喷.自己在牛刀小试的时候,发现系统的UIAlertView有点不喜欢,然后就自己自定义了一个UIAlertView,基本上实现了系统的UIAlertView,可以根据项目的需求修改UIAlertView的颜色.欢迎大神多多指导.不胜感激! 效果图: Paste_Image.png --------------直接贴代码---------不喜勿喷----------大神多多指导.不胜感激!------- #import <UIKit/UIKit.h> typedef void(^

设置警告框为带有一个密文输入框的样式,并设置输入框键盘为数字键盘;判断密文输入框里的内容,并弹出相应提示

项目需求 废话不说,直接上试题 及答案 代码 #import "TableViewController.h" @interface TableViewController ()<UIAlertViewDelegate> @property (nonatomic, strong) NSMutableArray * dataSource; - (IBAction)buy:(id)sender; @end @implementation TableViewController -

c#应用程序如何添加弹出式广告功能

使用c#语言,如何实现像搜狗输入法以及灵格斯翻译软件的屏幕右下角弹出式广告呢? c#code如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Run