252 lines
7.7 KiB
Swift
252 lines
7.7 KiB
Swift
|
|
//
|
|||
|
|
// 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
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|