当前位置: 首页 > news >正文

关于自定义 Alert

一、 window add subview

自定义 alert 的时候,没有做统一规划,都是实现一个 view,然后添加到 window 上。例如:

UIView *alert = [[UIView alloc] initWithFrame:];
[window addSubView:alert];
复制代码

这样本来也没有什么问题,有一天需求来了要支持 Voice Over,问题来了,直接盖上去的 view 不会自动聚焦,也就是手指左右滑动的时候,不能选中这个 view。而且不能 alert 出来的时候,不能自动读出。

二、利用Window 的 makeKeyAndVisible

然后想起以前 UIAlertView 显示的时候是有一个单独 window 的,于是也仿照 这样,自己建一个 window,来显示 alert,

    self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.alertWindow.rootViewController = [[UIViewController alloc] init];

    id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
    // Applications that does not load with UIMainStoryboardFile might not have a window property:
    if ([delegate respondsToSelector:@selector(window)]) {
        // we inherit the main window's tintColor
        self.alertWindow.tintColor = delegate.window.tintColor;
    }
    self.alertWindow.hidden = YES;
    self.frame = self.alertWindow.bounds;

    // window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
    UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
    self.alertWindow.windowLevel = topWindow.windowLevel + 1;

    [self.alertWindow makeKeyAndVisible];
    [self.alertWindow addSubview:self];


    [UIView animateWithDuration:0.25 animations:^{
        self.alertWindow.hidden = NO;
    } completion:nil];

复制代码

这样显示也正常,Voice Over 也能自动聚焦,但是 手指头不小心点到空白区域的时候,还是会聚焦到下面的 view,不能只在 alert 上。 而且还有一个严重的问题 就是 自定义密码输入空间,键盘有时候不会自动弹起来,这个以前是没问题的,不知道跟这个会不会有关系。

三、presentViewController

仿照 UIAlertController 的方式,利用 presentViewController来显示提示框,这个没有上面的问题,Voice over也能自定聚焦,也不会点到下面的 view。效果还可以。

    self.mShowInViewController.definesPresentationContext = YES;
    self.mShowInViewController.providesPresentationContextTransitionStyle = YES;

    if (!self.mShowViewController) {
        UIViewController *vc = [[UIViewController alloc] init];
        vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
        UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];
        backgroundView.backgroundColor = RGBA_COLOR_HEX(0x000000, 0.5);
        vc.backgroundView = backgroundView;
        if (self.alertType == CustomAlertTypeActionSheet) {
            UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClickBackground)];
            tap.delegate = self;
            [self addGestureRecognizer:tap];
        }
        
        [vc.view addSubview:backgroundView];
        vc.view.backgroundColor = [UIColor clearColor];
//        vc.backgroundView.alpha = 0;
        self.mShowViewController = vc;
    }
}

if (!self.superview) {
        [self.mShowViewController.view addSubview:self];
    }
    self.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    
    WEAKSELF
    [self.mShowInViewController presentViewController:self.mShowViewController animated:NO completion:^{
        [UIView animateWithDuration:0.25 animations:^{
            weak_self.mShowViewController.view.alpha = 1;
        } completion:^(BOOL finished) {
            if (complete) {
                complete(YES);
            }
        }];
    }];
复制代码

使用 presentViewController 的时候,由哪个ViewController来 present 也是个问题,统一处理的话,用跟 UITabBarController 或者是 UINavigationController都是不错的方案,例如:

UIViewController * root = [UIApplication sharedApplication].delegate.window.rootViewController;
        if ([root isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tab = (UITabBarController *)root;
            if (tab.tabBar.hidden) {
                //
                UIViewController *selectedVC = tab.selectedViewController;
                self.mShowInViewController = selectedVC;
            } else {
                self.mShowInViewController = root;
            }
        } else {
            self.mShowInViewController = root;
        }

复制代码

但是这里有问题,就是容易和其他的弹窗冲突,造成alert弹不出来,而且如果 alert 不释放的话,连弹多次还容易 crash

Application tried to present modally an active controller

所以呢可以把 Window 和 present结合起来使用。

alertWindow 一定要在 alert 消失的时候给释放掉

// method2: 问题是如果self 消失的时候不释放,那么 window 会一直存在接收事件,造成 rootWindow 无法接收事件
        self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.alertWindow.rootViewController = [[UIViewController alloc] init];
        
        id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
        // Applications that does not load with UIMainStoryboardFile might not have a window property:
        if ([delegate respondsToSelector:@selector(window)]) {
            // we inherit the main window's tintColor
            self.alertWindow.tintColor = delegate.window.tintColor;
        }
        
        // window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
        UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
        self.alertWindow.windowLevel = topWindow.windowLevel + 1;
        
        [self.alertWindow makeKeyAndVisible];
        self.mShowInViewController = self.alertWindow.rootViewController;


复制代码

四、完整代码

完整代码在这里

转载于:https://juejin.im/post/5c0a51a9518825428c56fe2b

相关文章:

  • C#练习4
  • python 基础语法 - 函数(一)
  • Mysql在sql中截取时间类型字段的年月日
  • 小议C#接口的隐式与显示实现
  • 【node】搭建自己的博客开坑(一)——项目的构思与设计——(后端部分)
  • linux内核管理--之定制一个属于自己的小型系统
  • 十二月技术考核:Windows系统故障排查
  • Android 之 内存管理
  • 尝试使用Open Live Writer写博客
  • 敏捷 扑克上的时间估算(转)
  • 码云新增GVP(最有价值)项目(10、11月合辑) | 码云周刊第 90 期
  • 您应该了解的 Windows Azure 网站在线工具
  • 多维数组拍平一层
  • Go语言的接口
  • IE9、 Firefox、Safari, Chrome的CSS3圆角属性
  • CentOS学习笔记 - 12. Nginx搭建Centos7.5远程repo
  • Docker 笔记(2):Dockerfile
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • jdbc就是这么简单
  • npx命令介绍
  • Octave 入门
  • Ruby 2.x 源代码分析:扩展 概述
  • 基于web的全景—— Pannellum小试
  • 面试遇到的一些题
  • 使用common-codec进行md5加密
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 数组的操作
  • 小程序01:wepy框架整合iview webapp UI
  • 由插件封装引出的一丢丢思考
  • 原生Ajax
  • 在weex里面使用chart图表
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • HanLP分词命名实体提取详解
  • ​力扣解法汇总946-验证栈序列
  • (6)添加vue-cookie
  • (差分)胡桃爱原石
  • (二)linux使用docker容器运行mysql
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (一)80c52学习之旅-起始篇
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (转)Oracle 9i 数据库设计指引全集(1)
  • (转)视频码率,帧率和分辨率的联系与区别
  • (转)树状数组
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • /var/spool/postfix/maildrop 下有大量文件
  • @EnableWebMvc介绍和使用详细demo
  • @ResponseBody
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [C#]winform制作仪表盘好用的表盘控件和使用方法