mirror of https://github.com/xaoxuu/ProHUD
适配iPad多窗口
This commit is contained in:
parent
27138a49e9
commit
b53a09ad75
|
@ -51,10 +51,8 @@ extension CALayer {
|
|||
var cornerRadiusWithContinuous: CGFloat {
|
||||
set {
|
||||
cornerRadius = newValue
|
||||
if #available(iOS 13.0, *) {
|
||||
if cornerCurve != .continuous {
|
||||
cornerCurve = .continuous
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
}
|
||||
get { cornerRadius }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<true/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import ProHUD
|
||||
|
||||
class ListVC: UITableViewController {
|
||||
|
||||
|
@ -46,6 +47,7 @@ class ListVC: UITableViewController {
|
|||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
AppContext.workspace = self
|
||||
list.sections[indexPath.section].rows[indexPath.row].action()
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import PackageDescription
|
|||
|
||||
let package = Package(
|
||||
name: "ProHUD",
|
||||
platforms: [.iOS(.v10)],
|
||||
platforms: [.iOS(.v13)],
|
||||
products: [
|
||||
.library(name: "ProHUD", targets: ["ProHUD"]),
|
||||
],
|
||||
|
|
|
@ -68,7 +68,8 @@ extension Alert: DefaultLayout {
|
|||
if contentView.superview != view {
|
||||
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.layer.shadowRadius = 4
|
||||
contentView.layer.shadowOpacity = 0.08
|
||||
|
@ -242,7 +243,8 @@ extension Alert {
|
|||
|
||||
public override func 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
import UIKit
|
||||
|
||||
extension Alert: HUD {
|
||||
|
||||
public func push(scene: UIWindowScene?) {
|
||||
push()
|
||||
}
|
||||
public func push() {
|
||||
guard AlertWindow.alerts.contains(self) == false else {
|
||||
let window = createAttachedWindowIfNotExists()
|
||||
guard window.alerts.contains(self) == false else {
|
||||
return
|
||||
}
|
||||
let window = attachedWindow
|
||||
view.transform = .init(scaleX: 1.2, y: 1.2)
|
||||
view.alpha = 0
|
||||
navEvents[.onViewWillAppear]?(self)
|
||||
|
@ -32,13 +34,13 @@ extension Alert: HUD {
|
|||
} completion: { done in
|
||||
self.navEvents[.onViewDidAppear]?(self)
|
||||
}
|
||||
AlertWindow.alerts.append(self)
|
||||
Alert.updateAlertsLayout()
|
||||
window.alerts.append(self)
|
||||
Alert.updateAlertsLayout(alerts: window.alerts)
|
||||
}
|
||||
|
||||
public func pop() {
|
||||
navEvents[.onViewWillDisappear]?(self)
|
||||
let window = attachedWindow
|
||||
let window = window ?? createAttachedWindowIfNotExists()
|
||||
Alert.removeAlert(alert: self)
|
||||
let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault
|
||||
UIView.animateEaseOut(duration: duration) {
|
||||
|
@ -50,13 +52,14 @@ extension Alert: HUD {
|
|||
self.navEvents[.onViewDidDisappear]?(self)
|
||||
}
|
||||
// hide window
|
||||
let count = AlertWindow.alerts.count
|
||||
if count == 0 && AlertWindow.current != nil {
|
||||
let count = window.alerts.count
|
||||
if count == 0 {
|
||||
UIView.animateEaseOut(duration: duration) {
|
||||
window.backgroundView.alpha = 0
|
||||
} completion: { done in
|
||||
if AlertWindow.alerts.count == 0 {
|
||||
AlertWindow.current = nil
|
||||
// 此时不能用self.window,因为alert已经释放掉了
|
||||
if window.alerts.count == 0, let scene = window.windowScene {
|
||||
AppContext.alertWindow[scene] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +75,7 @@ public extension Alert {
|
|||
/// - handler: 实例创建代码
|
||||
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)")
|
||||
if let vc = AlertWindow.alerts.last(where: { $0.identifier == id }) {
|
||||
if let vc = find(identifier: id).last {
|
||||
vc.update(handler: onExists ?? handler)
|
||||
} else {
|
||||
Alert { alert in
|
||||
|
@ -96,7 +99,7 @@ public extension Alert {
|
|||
/// - Parameter identifier: 唯一标识符
|
||||
/// - Returns: HUD实例
|
||||
@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 {
|
||||
arr.forEach({ $0.update(handler: handler) })
|
||||
}
|
||||
|
@ -106,8 +109,8 @@ public extension Alert {
|
|||
}
|
||||
|
||||
fileprivate extension Alert {
|
||||
static func updateAlertsLayout() {
|
||||
for (i, a) in AlertWindow.alerts.reversed().enumerated() {
|
||||
static func updateAlertsLayout(alerts: [Alert]) {
|
||||
for (i, a) in alerts.reversed().enumerated() {
|
||||
let scale = CGFloat(pow(0.9, CGFloat(i)))
|
||||
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)))
|
||||
|
@ -118,25 +121,29 @@ fileprivate extension Alert {
|
|||
}
|
||||
}
|
||||
|
||||
var attachedWindow: AlertWindow {
|
||||
AlertWindow.attachedWindow(config: config)
|
||||
func createAttachedWindowIfNotExists() -> AlertWindow {
|
||||
AlertWindow.createAttachedWindowIfNotExists(config: config)
|
||||
}
|
||||
|
||||
static func removeAlert(alert: Alert) {
|
||||
if AlertWindow.alerts.count > 1 {
|
||||
for (i, a) in AlertWindow.alerts.enumerated() {
|
||||
guard var alerts = alert.window?.alerts else {
|
||||
return
|
||||
}
|
||||
if alerts.count > 1 {
|
||||
for (i, a) in alerts.enumerated() {
|
||||
if a == alert {
|
||||
if i < AlertWindow.alerts.count {
|
||||
AlertWindow.alerts.remove(at: i)
|
||||
if i < alerts.count {
|
||||
alerts.remove(at: i)
|
||||
}
|
||||
}
|
||||
}
|
||||
updateAlertsLayout()
|
||||
} else if AlertWindow.alerts.count == 1 {
|
||||
AlertWindow.alerts.removeAll()
|
||||
updateAlertsLayout(alerts: alerts)
|
||||
} else if alerts.count == 1 {
|
||||
alerts.removeAll()
|
||||
} else {
|
||||
print("‼️代码漏洞:已经没有alert了")
|
||||
}
|
||||
alert.window?.alerts = alerts
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,29 +7,43 @@
|
|||
|
||||
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 {
|
||||
|
||||
static var current: AlertWindow?
|
||||
|
||||
static var alerts = [Alert]()
|
||||
var alerts: [Alert] = []
|
||||
|
||||
override var usingBackground: Bool { true }
|
||||
|
||||
static func attachedWindow(config: Configuration) -> AlertWindow {
|
||||
if let w = AlertWindow.current {
|
||||
static func createAttachedWindowIfNotExists(config: Configuration) -> AlertWindow {
|
||||
let windowScene = AppContext.windowScene
|
||||
if let windowScene = windowScene, let w = AppContext.alertWindow[windowScene] {
|
||||
return w
|
||||
}
|
||||
let w: AlertWindow
|
||||
if #available(iOS 13.0, *) {
|
||||
if let scene = AppContext.windowScene {
|
||||
w = .init(windowScene: scene)
|
||||
} else {
|
||||
w = .init(frame: AppContext.appBounds)
|
||||
}
|
||||
if let scene = windowScene {
|
||||
w = .init(windowScene: scene)
|
||||
} else {
|
||||
w = .init(frame: AppContext.appBounds)
|
||||
}
|
||||
AlertWindow.current = w
|
||||
if let windowScene = windowScene {
|
||||
AppContext.alertWindow[windowScene] = w
|
||||
}
|
||||
// 比原生alert层级低一点
|
||||
w.windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 1)
|
||||
return w
|
||||
|
|
|
@ -13,36 +13,26 @@ public class Configuration: NSObject {
|
|||
public static var enablePrint = true
|
||||
|
||||
public lazy var dynamicBackgroundColor: UIColor = {
|
||||
if #available(iOS 13.0, *) {
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .init(white: 0.15, alpha: 1)
|
||||
} else {
|
||||
return .init(white: 1, alpha: 1)
|
||||
}
|
||||
}
|
||||
return color
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .init(white: 0.15, alpha: 1)
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
return .init(white: 1, alpha: 1)
|
||||
}
|
||||
}
|
||||
return .init(white: 1, alpha: 1)
|
||||
return color
|
||||
}()
|
||||
|
||||
/// 动态颜色(适配iOS13)
|
||||
public lazy var dynamicTextColor: UIColor = {
|
||||
if #available(iOS 13.0, *) {
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .init(white: 1, alpha: 1)
|
||||
} else {
|
||||
return .init(white: 0.1, alpha: 1)
|
||||
}
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .init(white: 1, alpha: 1)
|
||||
} else {
|
||||
return .init(white: 0.1, alpha: 1)
|
||||
}
|
||||
return color
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
return .init(white: 0.1, alpha: 1)
|
||||
return color
|
||||
}()
|
||||
|
||||
/// 主标签文本颜色
|
||||
|
|
|
@ -5,9 +5,17 @@
|
|||
// Created by xaoxuu on 2022/8/29.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public protocol HUD {
|
||||
func push()
|
||||
func push(workspace: Workspace?)
|
||||
func pop()
|
||||
}
|
||||
|
||||
public extension HUD {
|
||||
func push(workspace: Workspace?) {
|
||||
AppContext.workspace = workspace
|
||||
push()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,41 +7,85 @@
|
|||
|
||||
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 {
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
private static var storedAppWindowScene: UIWindowScene?
|
||||
|
||||
private static var storedAppWindow: UIWindow?
|
||||
/// 一个scene关联一个toast
|
||||
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上
|
||||
/// workspace可以是windowScene/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 })
|
||||
}
|
||||
|
||||
/// 如果设置了workspace,就是workspace所对应的windowScene,否则就是最后一个打开的应用程序窗口的windowScene
|
||||
static var windowScene: UIWindowScene? {
|
||||
set { storedAppWindowScene = newValue }
|
||||
get {
|
||||
if let ws = storedAppWindowScene {
|
||||
return ws
|
||||
} else {
|
||||
return UIApplication.shared.connectedScenes.first(where: { scene in
|
||||
guard let ws = scene as? UIWindowScene else { return false }
|
||||
return ws.activationState == .foregroundActive
|
||||
}) as? UIWindowScene
|
||||
return foregroundActiveWindowScenes.last
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 所有的窗口
|
||||
static var windows: [UIWindow] {
|
||||
if #available(iOS 13.0, *) {
|
||||
return windowScene?.windows ?? UIApplication.shared.windows
|
||||
} else {
|
||||
return UIApplication.shared.windows
|
||||
}
|
||||
windowScene?.windows ?? UIApplication.shared.windows
|
||||
}
|
||||
|
||||
/// 可见的窗口
|
||||
|
@ -51,28 +95,31 @@ public extension AppContext {
|
|||
|
||||
/// App主程序窗口
|
||||
static var appWindow: UIWindow? {
|
||||
get {
|
||||
if let w = storedAppWindow {
|
||||
return w
|
||||
} else {
|
||||
return visibleWindows.filter { window in
|
||||
return "\(type(of: window))" == "UIWindow" && window.windowLevel == .normal
|
||||
}.first
|
||||
}
|
||||
}
|
||||
set { storedAppWindow = newValue }
|
||||
visibleWindows.filter { window in
|
||||
return "\(type(of: window))" == "UIWindow" && window.windowLevel == .normal
|
||||
}.first
|
||||
}
|
||||
|
||||
/// App主程序窗口的尺寸
|
||||
static var appBounds: CGRect {
|
||||
if #available(iOS 13.0, *) {
|
||||
return appWindow?.bounds ?? UIScreen.main.bounds
|
||||
} else {
|
||||
return UIScreen.main.bounds
|
||||
}
|
||||
appWindow?.bounds ?? UIScreen.main.bounds
|
||||
}
|
||||
|
||||
/// App主程序窗口的安全边距
|
||||
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] ?? []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,8 @@ extension CALayer {
|
|||
var cornerRadiusWithContinuous: CGFloat {
|
||||
set {
|
||||
cornerRadius = newValue
|
||||
if #available(iOS 13.0, *) {
|
||||
if cornerCurve != .continuous {
|
||||
cornerCurve = .continuous
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
}
|
||||
get { cornerRadius }
|
||||
|
|
|
@ -9,11 +9,7 @@ import UIKit
|
|||
|
||||
extension UIImage {
|
||||
public convenience init?(inProHUD named: String) {
|
||||
if #available(iOS 13.0, *) {
|
||||
self.init(named: named, in: .module, with: .none)
|
||||
} else {
|
||||
self.init(named: named)
|
||||
}
|
||||
self.init(named: named, in: .module, with: .none)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +20,7 @@ internal var isPortrait: Bool {
|
|||
return true
|
||||
}
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
if UIApplication.shared.statusBarOrientation.isPortrait {
|
||||
if AppContext.windowScene?.interfaceOrientation.isPortrait == true {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ class Window: UIWindow {
|
|||
rootViewController = vc
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
override init(windowScene: UIWindowScene) {
|
||||
super.init(windowScene: windowScene)
|
||||
setup()
|
||||
|
|
|
@ -51,7 +51,7 @@ public extension Sheet {
|
|||
/// - Parameter identifier: 唯一标识符
|
||||
/// - Returns: HUD实例
|
||||
@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 {
|
||||
arr.forEach({ $0.update(handler: handler) })
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// File.swift
|
||||
// SheetWindow.swift
|
||||
//
|
||||
//
|
||||
// Created by xaoxuu on 2022/9/8.
|
||||
|
@ -7,20 +7,30 @@
|
|||
|
||||
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
|
||||
|
||||
init(sheet: Sheet) {
|
||||
self.sheet = sheet
|
||||
if #available(iOS 13.0, *) {
|
||||
if let scene = AppContext.windowScene {
|
||||
super.init(windowScene: scene)
|
||||
} else {
|
||||
super.init(frame: AppContext.appBounds)
|
||||
}
|
||||
if let scene = AppContext.windowScene {
|
||||
super.init(windowScene: scene)
|
||||
} else {
|
||||
super.init(frame: AppContext.appBounds)
|
||||
}
|
||||
|
@ -36,6 +46,7 @@ class SheetWindow: Window {
|
|||
static func push(sheet: Sheet) {
|
||||
let isNew: Bool
|
||||
let window: SheetWindow
|
||||
var windows = AppContext.current?.sheetWindows ?? []
|
||||
if let w = windows.first(where: { $0.sheet == sheet }) {
|
||||
isNew = false
|
||||
window = w
|
||||
|
@ -46,6 +57,7 @@ class SheetWindow: Window {
|
|||
window.rootViewController = sheet
|
||||
if windows.contains(window) == false {
|
||||
windows.append(window)
|
||||
sheet.setContextWindows(windows)
|
||||
}
|
||||
if isNew {
|
||||
sheet.navEvents[.onViewWillAppear]?(sheet)
|
||||
|
@ -58,6 +70,7 @@ class SheetWindow: Window {
|
|||
}
|
||||
|
||||
static func pop(sheet: Sheet) {
|
||||
var windows = sheet.getContextWindows()
|
||||
guard let window = windows.first(where: { $0.sheet == sheet }) else {
|
||||
return
|
||||
}
|
||||
|
@ -72,6 +85,7 @@ class SheetWindow: Window {
|
|||
} else {
|
||||
consolePrint("‼️代码漏洞:已经没有sheet了")
|
||||
}
|
||||
sheet.setContextWindows(windows)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public extension Toast {
|
|||
/// - Parameter identifier: 唯一标识符
|
||||
/// - Returns: HUD实例
|
||||
@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 {
|
||||
arr.forEach({ $0.update(handler: handler) })
|
||||
}
|
||||
|
|
|
@ -7,9 +7,22 @@
|
|||
|
||||
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
|
||||
|
||||
|
@ -18,9 +31,7 @@ class ToastWindow: Window {
|
|||
init(toast: Toast) {
|
||||
self.toast = toast
|
||||
super.init(frame: .zero)
|
||||
if #available(iOS 13.0, *) {
|
||||
windowScene = AppContext.windowScene
|
||||
}
|
||||
windowScene = AppContext.windowScene
|
||||
toast.window = self
|
||||
windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue + 1000)
|
||||
layer.shadowRadius = 8
|
||||
|
@ -41,6 +52,7 @@ class ToastWindow: Window {
|
|||
static func push(toast: Toast) {
|
||||
let isNew: Bool
|
||||
let window: ToastWindow
|
||||
var windows = AppContext.current?.toastWindows ?? []
|
||||
if let w = windows.first(where: { $0.toast == toast }) {
|
||||
isNew = false
|
||||
window = w
|
||||
|
@ -64,8 +76,9 @@ class ToastWindow: Window {
|
|||
window.rootViewController = toast // 此时toast.view.frame.size会自动更新为window.frame.size
|
||||
if windows.contains(window) == false {
|
||||
windows.append(window)
|
||||
toast.setContextWindows(windows)
|
||||
}
|
||||
updateToastWindowsLayout()
|
||||
updateToastWindowsLayout(windows: windows)
|
||||
if isNew {
|
||||
window.transform = .init(translationX: 0, y: -window.frame.maxY)
|
||||
UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) {
|
||||
|
@ -80,24 +93,26 @@ class ToastWindow: Window {
|
|||
}
|
||||
|
||||
static func pop(toast: Toast) {
|
||||
var windows = toast.getContextWindows()
|
||||
guard let window = windows.first(where: { $0.toast == toast }) else {
|
||||
return
|
||||
}
|
||||
if windows.count > 1 {
|
||||
windows.removeAll { $0 == window }
|
||||
updateToastWindowsLayout()
|
||||
updateToastWindowsLayout(windows: windows)
|
||||
} else if windows.count == 1 {
|
||||
windows.removeAll()
|
||||
} else {
|
||||
consolePrint("‼️代码漏洞:已经没有toast了")
|
||||
}
|
||||
toast.vm.duration = nil
|
||||
toast.setContextWindows(windows)
|
||||
UIView.animateEaseOut(duration: toast.config.animateDurationForBuildOutByDefault) {
|
||||
window.transform = .init(translationX: 0, y: 0-20-window.maxY)
|
||||
} completion: { done in
|
||||
window.toast.view.removeFromSuperview()
|
||||
window.toast.removeFromParent()
|
||||
window.toast.navEvents[.onViewDidDisappear]?(window.toast)
|
||||
toast.view.removeFromSuperview()
|
||||
toast.removeFromParent()
|
||||
toast.navEvents[.onViewDidDisappear]?(toast)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +123,7 @@ fileprivate var updateToastsLayoutWorkItem: DispatchWorkItem?
|
|||
|
||||
fileprivate extension ToastWindow {
|
||||
|
||||
static func setToastWindowsLayout() {
|
||||
static func setToastWindowsLayout(windows: [ToastWindow]) {
|
||||
for (i, window) in windows.enumerated() {
|
||||
let config = window.toast.config
|
||||
var y = window.frame.origin.y
|
||||
|
@ -128,10 +143,10 @@ fileprivate extension ToastWindow {
|
|||
}
|
||||
}
|
||||
|
||||
static func updateToastWindowsLayout() {
|
||||
static func updateToastWindowsLayout(windows: [ToastWindow]) {
|
||||
updateToastsLayoutWorkItem?.cancel()
|
||||
updateToastsLayoutWorkItem = DispatchWorkItem {
|
||||
setToastWindowsLayout()
|
||||
setToastWindowsLayout(windows: windows)
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: updateToastsLayoutWorkItem!)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue