UIWindow的使用

APP从后台模式进入前台后打开指定页面

需求:前段时间在开发项目的时候,有一个需求,因为APP的一些信息比较敏感,所以如果用户在操作APP的过程中按下home键退到后台,超过指定的时间然后再切换到前台时,需要验证用户设置过的指纹或者是手势来对用户进行身份验证

方案一:

当APP进入前台的时候将 rootViewController 设置为指定的校验界面.

但是有一个问题:当用户验证成功之后呢? 如何回到用户之前操作过的界面呢? 暂时我没有好的解决方案, 如果你想到了好的idea,咱们可以一起探讨下~

方案二:

当APP进入前台的时候在当前界面上覆盖一个UIWindow,并设置UIWindowLevel,当用户验证成功之后在将该Window对象隐藏或者是移除即可

代码如下:

    func applicationDidEnterBackground(_ application: UIApplication) {
        leaveTime = Date()
    }
    func applicationWillEnterForeground(_ application: UIApplication) {
        let interval = Int(Date().timeIntervalSince(leaveTime))
        
        //这里假如超过20秒后就让用户去验证
        if interval > 20
        {
            let validateVC = ValidationVC()
            
            //当用户验证成功之后重新设置下windowLevel即可;
            validateVC.closeCallBack = {
                self.gestureWindow?.windowLevel = -1
            }
            let window = UIWindow(frame: UIScreen.main.bounds)
            window.windowLevel = UIWindowLevelAlert + 1
            window.rootViewController = validateVC
            window.makeKeyAndVisible()
            self.gestureWindow = window
        }
    }
    

UIWindowLevel

关于 UIWindowLevel 我想多说几句, UIWindow 在显示的时候会根据 UIWindowLevel 进行排序的,即 Level 高的将排在最前面.默认是 0

open var windowLevel: UIWindowLevel // default = 0.0

系统为我们定义了三个window层级,即:

public let UIWindowLevelNormal: UIWindowLevel
public let UIWindowLevelAlert: UIWindowLevel
public let UIWindowLevelStatusBar: UIWindowLevel

我们打印输出这三个level的值查看下:

STWLog("UIWindowLevelNormal: \(UIWindowLevelNormal)")
STWLog("UIWindowLevelStatusBar: \(UIWindowLevelStatusBar)")
STWLog("UIWindowLevelAlert: \(UIWindowLevelAlert)")

打印结果:

AppDelegate.swift:(43)----------UIWindowLevelNormal: 0.0
AppDelegate.swift:(44)----------UIWindowLevelStatusBar: 1000.0
AppDelegate.swift:(45)----------UIWindowLevelAlert: 2000.0

所以对于他们的级别我们也就一目了然了;

下面我们写个小Demo测试一下:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var normalWindow: UIWindow!
    var alertLevelWindow: UIWindow!
    var statusLevelWindow: UIWindow!
    var alertLevelWindow2: UIWindow!
   
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame:  CGRect(x: 0, y: 0, width: 100, height: 100))
        window?.tag = 10
        window?.backgroundColor = .red
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()
        
        //自定义Window,设置windowLevel为UIWindowLevelNormal
        normalWindow = UIWindow(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
        normalWindow?.tag = 100
        normalWindow.backgroundColor = .green
        normalWindow.windowLevel = UIWindowLevelNormal
        normalWindow.rootViewController = ViewController()
        normalWindow.makeKeyAndVisible()
        
       
        
        //自定义Window,设置windowLevel为UIWindowLevelNormal
        alertLevelWindow = UIWindow(frame: CGRect(x: 150, y: 150, width: 100, height: 100))
        alertLevelWindow?.tag = 10000
        alertLevelWindow.backgroundColor = .blue
        alertLevelWindow.windowLevel = UIWindowLevelAlert
        alertLevelWindow.rootViewController = ViewController()
        alertLevelWindow.makeKeyAndVisible()
        
        
        //自定义Window,设置windowLevel为UIWindowLevelStatusBar
        statusLevelWindow = UIWindow(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
        statusLevelWindow?.tag = 1000
        statusLevelWindow.backgroundColor = .yellow
        statusLevelWindow.windowLevel = UIWindowLevelStatusBar
        statusLevelWindow.rootViewController = ViewController()
        statusLevelWindow.makeKeyAndVisible()
        
        //自定义Window,设置windowLevel为UIWindowLevelStatusBar
        alertLevelWindow2 = UIWindow(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
        alertLevelWindow2?.tag = 100000
        alertLevelWindow2.backgroundColor = .white
        alertLevelWindow2.windowLevel = UIWindowLevelAlert + 10 //随意设置一个Level
        alertLevelWindow2.rootViewController = ViewController()
        alertLevelWindow2.makeKeyAndVisible()
        
        print("当前keyWindow: \(String(describing: UIApplication.shared.keyWindow!.tag))")
        
       return true
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
            self.alertLevelWindow2 = nil
        })
        
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 4.0, execute: {
            print("此时keyWindow: \(String(describing: UIApplication.shared.keyWindow!.tag))")
            
            for window in UIApplication.shared.windows
            {
                print("当前window的tag值为:\(window.tag)")
            }
        })
    }
}

运行结果如下图所示:

打印结果显示:

当前keyWindow: 100000
此时keyWindow: 10000
当前window的tag值为:0
当前window的tag值为:10
当前window的tag值为:100
当前window的tag值为:1000
当前window的tag值为:10000

什么是 keWindow ? 我们来查看下官方文档是怎么描述的:

也就是说在 windows 数组中,最近时间调用了 makeKeyAndVisible 方法的就是 keyWindow了;

总结:

  1. UIWindowLevel 的值不仅仅只有 UIWindowLevelNormalUIWindowLevelAlertUIWindowLevelStatusBar 这三个,可以是自定义的随意值,哪怕是负数
  2. UIWindow 的显示的确可以通过 UIWindowLevel 来区分优先级,所有的window都会被加在界面上,只不过会通过优先级罗列起来,UIWindowLevel 大的在上面显示,UIWindowLevel 小的在下面显示。
  3. UIWindowLevel 优先级相等的情况下,看谁后实例化了,谁后实例化谁先显示
  4. 如果将当前 KeyWindow对象设置为 nil 则该对象会从 Windows数组中移除,并且最后实例化的Window对象将成为 KeyWindow ,但是依然遵循总结2中的描述,UIWindowLevel 大的在上面显示,UIWindowLevel 小的在下面显示。

参考:
http://www.jianshu.com/p/f60471a7d935

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 一、问题背景 最近需求量放缓,想起了以前曾经later的小需求,也就是弹出来的AlertView中间的文本框输入一...
    唐笛_Dylan阅读 18,207评论 6 29
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,043评论 25 707
  • 每一个IOS程序都有一个UIWindow,在我们通过模板简历工程的时候,xcode会自动帮我们生成一个window...
    jumping鹏阅读 981评论 0 0
  • UIWindow 简介 一个UIWindow对象为应用程序的用户界面提供了背景以及重要的事件处理行为。UIWind...
    ripperhe阅读 23,141评论 24 58
  • 粉笔划过流年 留下青春的痕迹 铃声划过时空 送走回首的记忆 那些同桌的我和你 如今散落各地 那件白色的丑校服 如今...
    缀满星星的夜空只有我阅读 482评论 0 1