// // LevelStatusBarWindowController.swift // yinmeng-ios // // Created by MaiMang on 2024/2/2. // import Foundation public protocol LevelStatusBarWindowShowUpable { /// 打开状态 /// - Parameter superview: 父视图 func makeOpenedStatusConstraint(superview: UIView) /// 根据添加设置内容,刷新界面 func refreshBeforeShow() /// 显示 /// - Parameters: /// - animated: 是否动画效果 /// - animation: 动画内容 /// - completion: 完成回调 func show(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?) /// 关闭 /// - Parameters: /// - animated: 是否动画效果 /// - animation: 动画内容 /// - completion: 完成回调 func close(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?) } /// 状态窗口显示器 open class LevelStatusBarWindowController: UIViewController { private var isCalledClose = false private var canNotBeCanceled = false private var loadingCount: Int = 0 private lazy var lock = NSLock() private lazy var overlay: UIView = { let view = UIView(frame: self.view.bounds) view.backgroundColor = overlayBackgroundColor view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(overlayTap))) view.isUserInteractionEnabled = true return view }() public var key: String? public var showUpView: LevelStatusBarWindowShowUpable? /// 点击外面区域是否可关闭 public var canCloseWhenTapOutSize: Bool = true /// 外界已经将`showUpView`添加到控制器 public var addedShowUpView: Bool = false public var overlayBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.2) { didSet { self.overlay.backgroundColor = overlayBackgroundColor } } public func addedLoadingCount() { self.lock.lock() self.loadingCount += 1 self.lock.unlock() } public func subtractLoadingCount() -> Int { self.lock.lock() defer { self.lock.unlock() } self.loadingCount -= 1 return self.loadingCount } open override var prefersStatusBarHidden: Bool { if let controller = YMRequestX.topViewController() { return controller.prefersStatusBarHidden } return true } open override var preferredStatusBarStyle: UIStatusBarStyle { if let controller = YMRequestX.topViewController() { return controller.preferredStatusBarStyle } return .default } open override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.clear self.view.addSubview(self.overlay) if self.addedShowUpView { if let alertView = self.showUpView as? UIView { self.view.bringSubviewToFront(alertView) } } else if let alertView = self.showUpView as? UIView { self.view.addSubview(alertView) } self.showUpView?.makeOpenedStatusConstraint(superview: self.view) } private var overlayTapCloseBlock: ((LevelStatusBarWindowController) -> Void)? public func setOverlayTapCloseBlock(block: @escaping (LevelStatusBarWindowController) -> Void) { self.overlayTapCloseBlock = block } public func show(completion: ((Bool) -> Void)? = nil) { Self.controllers.removeAll { $0 == self } if let rootViewController = Self.window.rootViewController as? Self, !rootViewController.isCalledClose { Self.controllers.append(rootViewController) Self.window.rootViewController = nil } self.showUpView?.refreshBeforeShow() if Self.lastKeyWindow != Self.window { Self.lastKeyWindow = YMRequestX.keyWindow() } Self.window.isHidden = false Self.window.windowLevel = UIWindow.Level.statusBar Self.window.rootViewController = self Self.window.makeKeyAndVisible() self.overlay.alpha = 0 self.showUpView?.show(animated: true, animation: { [weak self] in self?.overlay.alpha = 1.0 self?.overlay.backgroundColor = self?.overlayBackgroundColor }, completion: completion) } public func close(animated: Bool = true) { self.isCalledClose = true self.showUpView?.close(animated: animated, animation: { [weak self] in self?.overlay.alpha = 0 }, completion: self.closeCompleted) } private func closeCompleted(_: Bool) { guard Self.window.rootViewController == self else { return } if let lastKeyWindow = Self.lastKeyWindow { if lastKeyWindow.rootViewController != nil { lastKeyWindow.makeKeyAndVisible() } Self.lastKeyWindow = nil } else if let window = UIApplication.shared.delegate?.window, window != nil { window?.makeKeyAndVisible() } Self.window.rootViewController = nil Self.window.isHidden = true if Self.controllers.count < 10 { while let rootViewController = Self.controllers.last { if rootViewController.isCalledClose { Self.controllers.removeLast() continue } rootViewController.show() break } } else { Self.controllers.removeAll() } } @objc private func overlayTap() { if canCloseWhenTapOutSize { close() overlayTapCloseBlock?(self) } } } extension LevelStatusBarWindowController { private static let window = UIWindow(frame: UIScreen.main.bounds) private static var lastKeyWindow: UIWindow? private static var controllers = [LevelStatusBarWindowController]() public static func cancelAllBackgroundControllersShow() { Self.controllers = Self.controllers.filter({ $0.canNotBeCanceled }) } public static func forcecancelAllControllers() { if let controller = Self.window.rootViewController as? LevelStatusBarWindowController, !controller.canNotBeCanceled { Self.window.rootViewController = nil Self.window.isHidden = true } cancelAllBackgroundControllersShow() } }