适配iPad多窗口

This commit is contained in:
xaoxuu 2023-08-06 14:36:41 +08:00
parent 27138a49e9
commit b53a09ad75
17 changed files with 218 additions and 128 deletions

View File

@ -51,10 +51,8 @@ extension CALayer {
var cornerRadiusWithContinuous: CGFloat { var cornerRadiusWithContinuous: CGFloat {
set { set {
cornerRadius = newValue cornerRadius = newValue
if #available(iOS 13.0, *) { if cornerCurve != .continuous {
cornerCurve = .continuous cornerCurve = .continuous
} else {
// Fallback on earlier versions
} }
} }
get { cornerRadius } get { cornerRadius }

View File

@ -5,7 +5,7 @@
<key>UIApplicationSceneManifest</key> <key>UIApplicationSceneManifest</key>
<dict> <dict>
<key>UIApplicationSupportsMultipleScenes</key> <key>UIApplicationSupportsMultipleScenes</key>
<false/> <true/>
<key>UISceneConfigurations</key> <key>UISceneConfigurations</key>
<dict> <dict>
<key>UIWindowSceneSessionRoleApplication</key> <key>UIWindowSceneSessionRoleApplication</key>

View File

@ -6,6 +6,7 @@
// //
import UIKit import UIKit
import ProHUD
class ListVC: UITableViewController { class ListVC: UITableViewController {
@ -46,6 +47,7 @@ class ListVC: UITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
AppContext.workspace = self
list.sections[indexPath.section].rows[indexPath.row].action() list.sections[indexPath.section].rows[indexPath.row].action()
} }

View File

@ -4,7 +4,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "ProHUD", name: "ProHUD",
platforms: [.iOS(.v10)], platforms: [.iOS(.v13)],
products: [ products: [
.library(name: "ProHUD", targets: ["ProHUD"]), .library(name: "ProHUD", targets: ["ProHUD"]),
], ],

View File

@ -68,7 +68,8 @@ extension Alert: DefaultLayout {
if contentView.superview != view { if contentView.superview != view {
view.insertSubview(contentView, at: 0) view.insertSubview(contentView, at: 0)
} }
if config.enableShadow && AlertWindow.alerts.count > 0 { let alerts = window?.alerts ?? []
if config.enableShadow && alerts.count > 0 {
contentView.clipsToBounds = false contentView.clipsToBounds = false
contentView.layer.shadowRadius = 4 contentView.layer.shadowRadius = 4
contentView.layer.shadowOpacity = 0.08 contentView.layer.shadowOpacity = 0.08
@ -242,7 +243,8 @@ extension Alert {
public override func viewDidLayoutSubviews() { public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
if config.enableShadow && AlertWindow.alerts.count > 1 { let alerts = window?.alerts ?? []
if config.enableShadow && alerts.count > 1 {
contentView.layer.shadowPath = UIBezierPath.init(rect: contentView.bounds).cgPath contentView.layer.shadowPath = UIBezierPath.init(rect: contentView.bounds).cgPath
} }
} }

View File

@ -8,12 +8,14 @@
import UIKit import UIKit
extension Alert: HUD { extension Alert: HUD {
public func push(scene: UIWindowScene?) {
push()
}
public func push() { public func push() {
guard AlertWindow.alerts.contains(self) == false else { let window = createAttachedWindowIfNotExists()
guard window.alerts.contains(self) == false else {
return return
} }
let window = attachedWindow
view.transform = .init(scaleX: 1.2, y: 1.2) view.transform = .init(scaleX: 1.2, y: 1.2)
view.alpha = 0 view.alpha = 0
navEvents[.onViewWillAppear]?(self) navEvents[.onViewWillAppear]?(self)
@ -32,13 +34,13 @@ extension Alert: HUD {
} completion: { done in } completion: { done in
self.navEvents[.onViewDidAppear]?(self) self.navEvents[.onViewDidAppear]?(self)
} }
AlertWindow.alerts.append(self) window.alerts.append(self)
Alert.updateAlertsLayout() Alert.updateAlertsLayout(alerts: window.alerts)
} }
public func pop() { public func pop() {
navEvents[.onViewWillDisappear]?(self) navEvents[.onViewWillDisappear]?(self)
let window = attachedWindow let window = window ?? createAttachedWindowIfNotExists()
Alert.removeAlert(alert: self) Alert.removeAlert(alert: self)
let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault
UIView.animateEaseOut(duration: duration) { UIView.animateEaseOut(duration: duration) {
@ -50,13 +52,14 @@ extension Alert: HUD {
self.navEvents[.onViewDidDisappear]?(self) self.navEvents[.onViewDidDisappear]?(self)
} }
// hide window // hide window
let count = AlertWindow.alerts.count let count = window.alerts.count
if count == 0 && AlertWindow.current != nil { if count == 0 {
UIView.animateEaseOut(duration: duration) { UIView.animateEaseOut(duration: duration) {
window.backgroundView.alpha = 0 window.backgroundView.alpha = 0
} completion: { done in } completion: { done in
if AlertWindow.alerts.count == 0 { // self.windowalert
AlertWindow.current = nil if window.alerts.count == 0, let scene = window.windowScene {
AppContext.alertWindow[scene] = nil
} }
} }
} }
@ -72,7 +75,7 @@ public extension Alert {
/// - handler: /// - handler:
static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ alert: Alert) -> Void, onExists: ((_ alert: Alert) -> Void)? = nil) { static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ alert: Alert) -> Void, onExists: ((_ alert: Alert) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)") let id = identifier ?? (file + "#\(line)")
if let vc = AlertWindow.alerts.last(where: { $0.identifier == id }) { if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler) vc.update(handler: onExists ?? handler)
} else { } else {
Alert { alert in Alert { alert in
@ -96,7 +99,7 @@ public extension Alert {
/// - Parameter identifier: /// - Parameter identifier:
/// - Returns: HUD /// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ alert: Alert) -> Void)? = nil) -> [Alert] { @discardableResult static func find(identifier: String, update handler: ((_ alert: Alert) -> Void)? = nil) -> [Alert] {
let arr = AlertWindow.alerts.filter({ $0.identifier == identifier }) let arr = AppContext.alertWindow.values.flatMap({ $0.alerts }).filter({ $0.identifier == identifier })
if let handler = handler { if let handler = handler {
arr.forEach({ $0.update(handler: handler) }) arr.forEach({ $0.update(handler: handler) })
} }
@ -106,8 +109,8 @@ public extension Alert {
} }
fileprivate extension Alert { fileprivate extension Alert {
static func updateAlertsLayout() { static func updateAlertsLayout(alerts: [Alert]) {
for (i, a) in AlertWindow.alerts.reversed().enumerated() { for (i, a) in alerts.reversed().enumerated() {
let scale = CGFloat(pow(0.9, CGFloat(i))) let scale = CGFloat(pow(0.9, CGFloat(i)))
UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: { UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: {
let y = 0 - a.config.stackDepth * CGFloat(i) * CGFloat(pow(0.85, CGFloat(i))) let y = 0 - a.config.stackDepth * CGFloat(i) * CGFloat(pow(0.85, CGFloat(i)))
@ -118,25 +121,29 @@ fileprivate extension Alert {
} }
} }
var attachedWindow: AlertWindow { func createAttachedWindowIfNotExists() -> AlertWindow {
AlertWindow.attachedWindow(config: config) AlertWindow.createAttachedWindowIfNotExists(config: config)
} }
static func removeAlert(alert: Alert) { static func removeAlert(alert: Alert) {
if AlertWindow.alerts.count > 1 { guard var alerts = alert.window?.alerts else {
for (i, a) in AlertWindow.alerts.enumerated() { return
}
if alerts.count > 1 {
for (i, a) in alerts.enumerated() {
if a == alert { if a == alert {
if i < AlertWindow.alerts.count { if i < alerts.count {
AlertWindow.alerts.remove(at: i) alerts.remove(at: i)
} }
} }
} }
updateAlertsLayout() updateAlertsLayout(alerts: alerts)
} else if AlertWindow.alerts.count == 1 { } else if alerts.count == 1 {
AlertWindow.alerts.removeAll() alerts.removeAll()
} else { } else {
print("代码漏洞已经没有alert了") print("代码漏洞已经没有alert了")
} }
alert.window?.alerts = alerts
} }
} }

View File

@ -7,29 +7,43 @@
import UIKit import UIKit
extension Alert {
var window: AlertWindow? {
get {
guard let windowScene = windowScene else {
return nil
}
return AppContext.alertWindow[windowScene]
}
set {
guard let windowScene = windowScene else {
return
}
AppContext.alertWindow[windowScene] = newValue
}
}
}
class AlertWindow: Window { class AlertWindow: Window {
static var current: AlertWindow? var alerts: [Alert] = []
static var alerts = [Alert]()
override var usingBackground: Bool { true } override var usingBackground: Bool { true }
static func attachedWindow(config: Configuration) -> AlertWindow { static func createAttachedWindowIfNotExists(config: Configuration) -> AlertWindow {
if let w = AlertWindow.current { let windowScene = AppContext.windowScene
if let windowScene = windowScene, let w = AppContext.alertWindow[windowScene] {
return w return w
} }
let w: AlertWindow let w: AlertWindow
if #available(iOS 13.0, *) { if let scene = windowScene {
if let scene = AppContext.windowScene {
w = .init(windowScene: scene) w = .init(windowScene: scene)
} else { } else {
w = .init(frame: AppContext.appBounds) w = .init(frame: AppContext.appBounds)
} }
} else { if let windowScene = windowScene {
w = .init(frame: AppContext.appBounds) AppContext.alertWindow[windowScene] = w
} }
AlertWindow.current = w
// alert // alert
w.windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 1) w.windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 1)
return w return w

View File

@ -13,7 +13,6 @@ public class Configuration: NSObject {
public static var enablePrint = true public static var enablePrint = true
public lazy var dynamicBackgroundColor: UIColor = { public lazy var dynamicBackgroundColor: UIColor = {
if #available(iOS 13.0, *) {
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
if traitCollection.userInterfaceStyle == .dark { if traitCollection.userInterfaceStyle == .dark {
return .init(white: 0.15, alpha: 1) return .init(white: 0.15, alpha: 1)
@ -22,15 +21,10 @@ public class Configuration: NSObject {
} }
} }
return color return color
} else {
// Fallback on earlier versions
}
return .init(white: 1, alpha: 1)
}() }()
/// iOS13 /// iOS13
public lazy var dynamicTextColor: UIColor = { public lazy var dynamicTextColor: UIColor = {
if #available(iOS 13.0, *) {
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
if traitCollection.userInterfaceStyle == .dark { if traitCollection.userInterfaceStyle == .dark {
return .init(white: 1, alpha: 1) return .init(white: 1, alpha: 1)
@ -39,10 +33,6 @@ public class Configuration: NSObject {
} }
} }
return color return color
} else {
// Fallback on earlier versions
}
return .init(white: 0.1, alpha: 1)
}() }()
/// ///

View File

@ -5,9 +5,17 @@
// Created by xaoxuu on 2022/8/29. // Created by xaoxuu on 2022/8/29.
// //
import Foundation import UIKit
public protocol HUD { public protocol HUD {
func push() func push()
func push(workspace: Workspace?)
func pop() func pop()
} }
public extension HUD {
func push(workspace: Workspace?) {
AppContext.workspace = workspace
push()
}
}

View File

@ -7,41 +7,85 @@
import UIKit import UIKit
public protocol Workspace {}
extension UIWindowScene: Workspace {}
extension UIView: Workspace {}
extension UIViewController: Workspace {}
extension Workspace {
var windowScene: UIWindowScene? {
if let self = self as? UIWindowScene {
return self
} else if let self = self as? UIWindow {
return self.windowScene
} else if let self = self as? UIView {
return self.window?.windowScene
} else if let self = self as? UIViewController {
return self.view.window?.windowScene
}
return nil
}
}
public struct AppContext { public struct AppContext {
@available(iOS 13.0, *)
private static var storedAppWindowScene: UIWindowScene? private static var storedAppWindowScene: UIWindowScene?
private static var storedAppWindow: UIWindow? /// scenetoast
static var toastWindows: [UIWindowScene: [ToastWindow]] = [:]
static var alertWindow: [UIWindowScene: AlertWindow] = [:]
static var sheetWindows: [UIWindowScene: [SheetWindow]] = [:]
private init() {} static var current: AppContext? {
guard let windowScene = windowScene else { return nil }
if let ctx = allContexts[windowScene] {
return ctx
} else {
let ctx: AppContext = .init(windowScene: windowScene)
allContexts[windowScene] = ctx
return ctx
}
}
static var allContexts = [UIWindowScene: AppContext]()
private let windowScene: UIWindowScene
private init(windowScene: UIWindowScene) {
self.windowScene = windowScene
}
/// windowScene
/// workspacewindowScene/window/view/viewController
public static var workspace: Workspace? {
get { windowScene }
set {
windowScene = newValue?.windowScene
}
}
} }
public extension AppContext { extension AppContext {
@available(iOS 13.0, *) static var foregroundActiveWindowScenes: [UIWindowScene] {
return UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).filter({ $0.activationState == .foregroundActive })
}
/// workspaceworkspacewindowScenewindowScene
static var windowScene: UIWindowScene? { static var windowScene: UIWindowScene? {
set { storedAppWindowScene = newValue } set { storedAppWindowScene = newValue }
get { get {
if let ws = storedAppWindowScene { if let ws = storedAppWindowScene {
return ws return ws
} else { } else {
return UIApplication.shared.connectedScenes.first(where: { scene in return foregroundActiveWindowScenes.last
guard let ws = scene as? UIWindowScene else { return false }
return ws.activationState == .foregroundActive
}) as? UIWindowScene
} }
} }
} }
/// ///
static var windows: [UIWindow] { static var windows: [UIWindow] {
if #available(iOS 13.0, *) { windowScene?.windows ?? UIApplication.shared.windows
return windowScene?.windows ?? UIApplication.shared.windows
} else {
return UIApplication.shared.windows
}
} }
/// ///
@ -51,28 +95,31 @@ public extension AppContext {
/// App /// App
static var appWindow: UIWindow? { static var appWindow: UIWindow? {
get { visibleWindows.filter { window in
if let w = storedAppWindow {
return w
} else {
return visibleWindows.filter { window in
return "\(type(of: window))" == "UIWindow" && window.windowLevel == .normal return "\(type(of: window))" == "UIWindow" && window.windowLevel == .normal
}.first }.first
} }
}
set { storedAppWindow = newValue }
}
/// App /// App
static var appBounds: CGRect { static var appBounds: CGRect {
if #available(iOS 13.0, *) { appWindow?.bounds ?? UIScreen.main.bounds
return appWindow?.bounds ?? UIScreen.main.bounds
} else {
return UIScreen.main.bounds
}
} }
/// App /// App
static var safeAreaInsets: UIEdgeInsets { appWindow?.safeAreaInsets ?? .zero } static var safeAreaInsets: UIEdgeInsets { appWindow?.safeAreaInsets ?? .zero }
} }
// MARK: - instance manage
extension AppContext {
var sheetWindows: [SheetWindow] {
Self.sheetWindows[windowScene] ?? []
}
}
extension AppContext {
var toastWindows: [ToastWindow] {
Self.toastWindows[windowScene] ?? []
}
}

View File

@ -13,10 +13,8 @@ extension CALayer {
var cornerRadiusWithContinuous: CGFloat { var cornerRadiusWithContinuous: CGFloat {
set { set {
cornerRadius = newValue cornerRadius = newValue
if #available(iOS 13.0, *) { if cornerCurve != .continuous {
cornerCurve = .continuous cornerCurve = .continuous
} else {
// Fallback on earlier versions
} }
} }
get { cornerRadius } get { cornerRadius }

View File

@ -9,11 +9,7 @@ import UIKit
extension UIImage { extension UIImage {
public convenience init?(inProHUD named: String) { public convenience init?(inProHUD named: String) {
if #available(iOS 13.0, *) {
self.init(named: named, in: .module, with: .none) self.init(named: named, in: .module, with: .none)
} else {
self.init(named: named)
}
} }
} }
@ -24,7 +20,7 @@ internal var isPortrait: Bool {
return true return true
} }
if UIDevice.current.userInterfaceIdiom == .phone { if UIDevice.current.userInterfaceIdiom == .phone {
if UIApplication.shared.statusBarOrientation.isPortrait { if AppContext.windowScene?.interfaceOrientation.isPortrait == true {
return true return true
} }
} }

View File

@ -41,7 +41,6 @@ class Window: UIWindow {
rootViewController = vc rootViewController = vc
} }
@available(iOS 13.0, *)
override init(windowScene: UIWindowScene) { override init(windowScene: UIWindowScene) {
super.init(windowScene: windowScene) super.init(windowScene: windowScene)
setup() setup()

View File

@ -51,7 +51,7 @@ public extension Sheet {
/// - Parameter identifier: /// - Parameter identifier:
/// - Returns: HUD /// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ sheet: Sheet) -> Void)? = nil) -> [Sheet] { @discardableResult static func find(identifier: String, update handler: ((_ sheet: Sheet) -> Void)? = nil) -> [Sheet] {
let arr = SheetWindow.windows.compactMap({ $0.sheet }).filter({ $0.identifier == identifier }) let arr = AppContext.sheetWindows.values.flatMap({ $0 }).compactMap({ $0.sheet }).filter({ $0.identifier == identifier })
if let handler = handler { if let handler = handler {
arr.forEach({ $0.update(handler: handler) }) arr.forEach({ $0.update(handler: handler) })
} }

View File

@ -1,5 +1,5 @@
// //
// File.swift // SheetWindow.swift
// //
// //
// Created by xaoxuu on 2022/9/8. // Created by xaoxuu on 2022/9/8.
@ -7,23 +7,33 @@
import UIKit import UIKit
class SheetWindow: Window {
static var windows = [SheetWindow]() private extension Sheet {
func getContextWindows() -> [SheetWindow] {
guard let windowScene = windowScene else {
return []
}
return AppContext.sheetWindows[windowScene] ?? []
}
func setContextWindows(_ windows: [SheetWindow]) {
guard let windowScene = windowScene else {
return
}
AppContext.sheetWindows[windowScene] = windows
}
}
class SheetWindow: Window {
var sheet: Sheet var sheet: Sheet
init(sheet: Sheet) { init(sheet: Sheet) {
self.sheet = sheet self.sheet = sheet
if #available(iOS 13.0, *) {
if let scene = AppContext.windowScene { if let scene = AppContext.windowScene {
super.init(windowScene: scene) super.init(windowScene: scene)
} else { } else {
super.init(frame: AppContext.appBounds) super.init(frame: AppContext.appBounds)
} }
} else {
super.init(frame: AppContext.appBounds)
}
sheet.window = self sheet.window = self
windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 2) windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 2)
isHidden = false isHidden = false
@ -36,6 +46,7 @@ class SheetWindow: Window {
static func push(sheet: Sheet) { static func push(sheet: Sheet) {
let isNew: Bool let isNew: Bool
let window: SheetWindow let window: SheetWindow
var windows = AppContext.current?.sheetWindows ?? []
if let w = windows.first(where: { $0.sheet == sheet }) { if let w = windows.first(where: { $0.sheet == sheet }) {
isNew = false isNew = false
window = w window = w
@ -46,6 +57,7 @@ class SheetWindow: Window {
window.rootViewController = sheet window.rootViewController = sheet
if windows.contains(window) == false { if windows.contains(window) == false {
windows.append(window) windows.append(window)
sheet.setContextWindows(windows)
} }
if isNew { if isNew {
sheet.navEvents[.onViewWillAppear]?(sheet) sheet.navEvents[.onViewWillAppear]?(sheet)
@ -58,6 +70,7 @@ class SheetWindow: Window {
} }
static func pop(sheet: Sheet) { static func pop(sheet: Sheet) {
var windows = sheet.getContextWindows()
guard let window = windows.first(where: { $0.sheet == sheet }) else { guard let window = windows.first(where: { $0.sheet == sheet }) else {
return return
} }
@ -72,6 +85,7 @@ class SheetWindow: Window {
} else { } else {
consolePrint("代码漏洞已经没有sheet了") consolePrint("代码漏洞已经没有sheet了")
} }
sheet.setContextWindows(windows)
} }
} }
} }

View File

@ -51,7 +51,7 @@ public extension Toast {
/// - Parameter identifier: /// - Parameter identifier:
/// - Returns: HUD /// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ toast: Toast) -> Void)? = nil) -> [Toast] { @discardableResult static func find(identifier: String, update handler: ((_ toast: Toast) -> Void)? = nil) -> [Toast] {
let arr = ToastWindow.windows.compactMap({ $0.toast }).filter({ $0.identifier == identifier }) let arr = AppContext.toastWindows.values.flatMap({ $0 }).compactMap({ $0.toast }).filter({ $0.identifier == identifier })
if let handler = handler { if let handler = handler {
arr.forEach({ $0.update(handler: handler) }) arr.forEach({ $0.update(handler: handler) })
} }

View File

@ -7,9 +7,22 @@
import UIKit import UIKit
class ToastWindow: Window { private extension Toast {
func getContextWindows() -> [ToastWindow] {
guard let windowScene = windowScene else {
return []
}
return AppContext.toastWindows[windowScene] ?? []
}
func setContextWindows(_ windows: [ToastWindow]) {
guard let windowScene = windowScene else {
return
}
AppContext.toastWindows[windowScene] = windows
}
}
static var windows = [ToastWindow]() class ToastWindow: Window {
var toast: Toast var toast: Toast
@ -18,9 +31,7 @@ class ToastWindow: Window {
init(toast: Toast) { init(toast: Toast) {
self.toast = toast self.toast = toast
super.init(frame: .zero) super.init(frame: .zero)
if #available(iOS 13.0, *) {
windowScene = AppContext.windowScene windowScene = AppContext.windowScene
}
toast.window = self toast.window = self
windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue + 1000) windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue + 1000)
layer.shadowRadius = 8 layer.shadowRadius = 8
@ -41,6 +52,7 @@ class ToastWindow: Window {
static func push(toast: Toast) { static func push(toast: Toast) {
let isNew: Bool let isNew: Bool
let window: ToastWindow let window: ToastWindow
var windows = AppContext.current?.toastWindows ?? []
if let w = windows.first(where: { $0.toast == toast }) { if let w = windows.first(where: { $0.toast == toast }) {
isNew = false isNew = false
window = w window = w
@ -64,8 +76,9 @@ class ToastWindow: Window {
window.rootViewController = toast // toast.view.frame.sizewindow.frame.size window.rootViewController = toast // toast.view.frame.sizewindow.frame.size
if windows.contains(window) == false { if windows.contains(window) == false {
windows.append(window) windows.append(window)
toast.setContextWindows(windows)
} }
updateToastWindowsLayout() updateToastWindowsLayout(windows: windows)
if isNew { if isNew {
window.transform = .init(translationX: 0, y: -window.frame.maxY) window.transform = .init(translationX: 0, y: -window.frame.maxY)
UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) { UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) {
@ -80,24 +93,26 @@ class ToastWindow: Window {
} }
static func pop(toast: Toast) { static func pop(toast: Toast) {
var windows = toast.getContextWindows()
guard let window = windows.first(where: { $0.toast == toast }) else { guard let window = windows.first(where: { $0.toast == toast }) else {
return return
} }
if windows.count > 1 { if windows.count > 1 {
windows.removeAll { $0 == window } windows.removeAll { $0 == window }
updateToastWindowsLayout() updateToastWindowsLayout(windows: windows)
} else if windows.count == 1 { } else if windows.count == 1 {
windows.removeAll() windows.removeAll()
} else { } else {
consolePrint("代码漏洞已经没有toast了") consolePrint("代码漏洞已经没有toast了")
} }
toast.vm.duration = nil toast.vm.duration = nil
toast.setContextWindows(windows)
UIView.animateEaseOut(duration: toast.config.animateDurationForBuildOutByDefault) { UIView.animateEaseOut(duration: toast.config.animateDurationForBuildOutByDefault) {
window.transform = .init(translationX: 0, y: 0-20-window.maxY) window.transform = .init(translationX: 0, y: 0-20-window.maxY)
} completion: { done in } completion: { done in
window.toast.view.removeFromSuperview() toast.view.removeFromSuperview()
window.toast.removeFromParent() toast.removeFromParent()
window.toast.navEvents[.onViewDidDisappear]?(window.toast) toast.navEvents[.onViewDidDisappear]?(toast)
} }
} }
@ -108,7 +123,7 @@ fileprivate var updateToastsLayoutWorkItem: DispatchWorkItem?
fileprivate extension ToastWindow { fileprivate extension ToastWindow {
static func setToastWindowsLayout() { static func setToastWindowsLayout(windows: [ToastWindow]) {
for (i, window) in windows.enumerated() { for (i, window) in windows.enumerated() {
let config = window.toast.config let config = window.toast.config
var y = window.frame.origin.y var y = window.frame.origin.y
@ -128,10 +143,10 @@ fileprivate extension ToastWindow {
} }
} }
static func updateToastWindowsLayout() { static func updateToastWindowsLayout(windows: [ToastWindow]) {
updateToastsLayoutWorkItem?.cancel() updateToastsLayoutWorkItem?.cancel()
updateToastsLayoutWorkItem = DispatchWorkItem { updateToastsLayoutWorkItem = DispatchWorkItem {
setToastWindowsLayout() setToastWindowsLayout(windows: windows)
} }
DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: updateToastsLayoutWorkItem!) DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: updateToastsLayoutWorkItem!)
} }