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)")
            }
        })
    }
}

运行结果如下图所示:

UIWindow的使用_第1张图片

打印结果显示:

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

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

UIWindow的使用_第2张图片

也就是说在 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

你可能感兴趣的:(UIWindow的使用)