// // UIWindow+Ext.swift // DouYinSwift5 // // Created by lym on 2020/7/23. // Copyright © 2020 lym. All rights reserved. // import UIKit @objc extension UIWindow { static var key: UIWindow? { if #available(iOS 13, *) { return UIApplication.shared.connectedScenes .map { $0 as? UIWindowScene } .compactMap { $0 } .first?.windows .filter { $0.isKeyWindow }.first } else { return UIApplication.shared.windows .filter { $0.isKeyWindow } .first } } static var applicationKey: UIWindow? { if #available(iOS 13, *) { var window: UIWindow? let connectedScenes = UIApplication.shared.connectedScenes .map { $0 as? UIWindowScene } .compactMap { $0 } connectedScenes.forEach { scene in window = scene.windows.filter { $0.tag == 1024 }.first } return window } else { return UIApplication.shared.windows.first(where: { $0.tag == 1024 }) } } /// 获取当前激活的 SceneDelegate static var currentSceneDelegate: SceneDelegate? { if let scene = UIApplication.shared.connectedScenes .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { return scene.delegate as? SceneDelegate } return nil } /// 获取当前激活窗口 static var current: UIWindow? { if let scene = UIApplication.shared.connectedScenes .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { return scene.windows.first(where: { $0.isKeyWindow }) } return nil } static var safeAreaInsets: UIEdgeInsets { return UIWindow.key?.safeAreaInsets ?? UIEdgeInsets.zero } static var safeAreaBottom: CGFloat { return safeAreaInsets.bottom } static var statusBarFrame: CGRect { if #available(iOS 13.0, *) { return key?.windowScene?.statusBarManager?.statusBarFrame ?? .zero } else { return UIApplication.shared.statusBarFrame } } static var statusBarHeight: CGFloat { return statusBarFrame.size.height } static var navBarHeight: CGFloat { return getTopViewController()?.navigationController?.navigationBar.frame.height ?? 44 } static var navBarTotalHeight: CGFloat { return statusBarHeight + navBarHeight } static var tabBarFrame: CGRect { if let vc = key?.rootViewController as? UITabBarController { if #available(iOS 11.0, *) { return vc.tabBar.frame } else { return .zero } } else { return .zero } } static var tabBarHeight: CGFloat { if #available(iOS 11.0, *) { return tabBarTotalHeight - (key?.safeAreaInsets.bottom ?? 0) } else { return tabBarTotalHeight } } static var tabBarTotalHeight: CGFloat { return tabBarFrame.height } class func getTopViewController(base: UIViewController? = UIWindow.getTopDisplayWindow()?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return getTopViewController(base: nav.viewControllers.last) } else if let tab = base as? UITabBarController, let selected = tab.selectedViewController { return getTopViewController(base: selected) } else if let presented = base?.presentedViewController { return getTopViewController(base: presented) } return base } class func getTopNavigationController() -> CLNavigationController?{ return getTopViewController()?.navigationController as? CLNavigationController } class func getTopDisplayWindow() -> UIWindow? { var theWindow = applicationKey let windows = UIApplication.shared.windows // windows.forEach { w in // dlog("获取的windows getTopDisplayWindow = \(w.self), isKey = \(w.isKeyWindow)") // } for window in windows.reversed() { // 需要过滤掉的类型 // ⚠️ Swift创建的Window为{ProjectName}.NoticeWindow,带命名空间,注意判断逻辑的写法:NSClassFromString("LegendTeam.NoticeWindow")or window.isKind(of: NoticeWindow.self) // if window.isKind(of: NoticeWindow.self) { // continue // } // UIRemoteKeyboardWindow // UITextEffectsWindow if let class1 = NSClassFromString("UIRemoteKeyboardWindow") { if window.isKind(of: class1) { //dlog("过滤掉的window UIRemoteKeyboardWindow") continue } } if let class2 = NSClassFromString("UITextEffectsWindow") { if window.isKind(of: class2) { //dlog("过滤掉的window UITextEffectsWindow") continue } } if let class3 = NSClassFromString("EGChatRoomFloatWindow") { if window.isKind(of: class3) { //dlog("过滤掉的window EGChatRoomFloatWindow") continue } } if let class4 = NSClassFromString("PhoneFloatWindow") { if window.isKind(of: class4) { //dlog("过滤掉的window PhoneFloatWindow") continue } } if let class5 = NSClassFromString("PhoneWindow") { if window.isKind(of: class5) { //dlog("过滤掉的window PhoneWindow") continue } } // if ChatRoomRoute.isMiniMize() { // if let class4 = NSClassFromString("ChatRoomWindow") { // if window.isKind(of: class4) { // dlog("过滤掉的window ChatRoomWindow, 聊天室缩小状态") // continue // } // } // } if !window.isHidden, window.alpha == 1 { theWindow = window // dlog("获取的window2 = \(window), type = \(window.self)") break } } return theWindow } } extension UIScreen { static var width: CGFloat { return UIScreen.main.bounds.width } static var height: CGFloat { return UIScreen.main.bounds.height } /// 屏幕尺寸(CGSize) static var size: CGSize { return UIScreen.main.bounds.size } /// 屏幕比例(宽 / 高) static var aspectRatio: CGFloat { return width / height } /// 是否是窄屏(如 iPhone SE) static var isNarrow: Bool { return width <= 320 } } extension UIDevice { static var isIphoneX: Bool { if UIDevice.current.userInterfaceIdiom != .phone { return true } if #available(iOS 11.0, *) { let bottom = UIWindow.safeAreaInsets.bottom if bottom > 0.0 { return true } } return false } /// 获取屏幕系数缩放后的值 static func DP(x: CGFloat) -> CGFloat { let standardWidth: CGFloat = 375.0 let scale = UIScreen.width / standardWidth return x * scale } /// 获取屏幕系数缩放后的值,最大不超过原值 static func DP(max: CGFloat) -> CGFloat { let x = DP(x: max) if x > max { return max } else { return x } } }