diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift index f9a9b07..cc7cad0 100644 --- a/Example/Example/ViewController.swift +++ b/Example/Example/ViewController.swift @@ -41,26 +41,34 @@ class ViewController: UIViewController { // // }.addAction(style: .cancel, title: "取消", action: nil).didDisappear { // debugPrint("didDisappear") +// }.addAction(style: .cancel, title: nil) { +// // } -// let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "哈哈") -// let a = ProHUD.show(alert: .loading, title: "正在加载", message: "请坐和放宽") -// a.didMinimize { -// hud.show(t) -// } -// t.didTapped { [weak t] in -// hud.show(a) -// t?.remove() -// } - -// a.didMinimize { -// ProHUD.show(toast: .loading, title: "正在加载", message: "哈哈").didTapped { -// ProHUD.show(toast: .loading, title: "正在加载", message: "哈克里斯蒂娜疯狂拉升的反馈老实交代分开就撒开了击快乐圣诞哈克里斯蒂娜疯狂拉升的反馈老实交代分开就撒开了击快乐圣诞") -// } -// } + let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻") + + let a = ProHUD.show(alert : .loading, title: "正在加载", message: "请稍候片刻") + a.didMinimize { + hud.show(t) + } + t.didTapped { [weak t] in + t?.remove() + let a2 = ProHUD.show(alert: .loading, title: "正在加载", message: "马上就要成功了") + DispatchQueue.main.asyncAfter(deadline: .now()+1) { + a2.updateContent(scene: .error, title: "加载失败", message: "点击充实") + a2.addAction(style: .default, title: "重新加载") { [weak a2] in + a2?.updateContent(scene: .success, title: "加载成功", message: "马上就要成功了") + a2?.updateAction(index: 0, style: .default, title: "OK", action: { [weak a2] in + a2?.remove() + }).removeAction(index: 1).removeAction(index: 1) + }.addAction(style: .destructive, title: "终止", action: nil).addAction(style: .cancel, title: "取消", action: nil) + + } + + } - ProHUD.show(toast: .loading, title: "正在加载", message: "拉升的反馈老实交代分开就撒开了击快乐圣反馈老实交代分开就撒开了击快乐圣") +// ProHUD.show(toast: .loading, title: "正在加载", message: "拉升的反馈老实交代分开就撒开了击快乐圣反馈老实交代分开就撒开了击快乐圣") // ProHUD.show(toast: .loading, title: "正在加载", message: "哈克里斯蒂娜疯狂拉升的反馈老实交代分开就撒开了击快乐圣诞哈克里斯蒂娜疯狂拉升的反馈老实交代分开就撒开了击快乐圣诞") DispatchQueue.main.asyncAfter(deadline: .now()+1) { diff --git a/ProHUD/Alert/AlertController.swift b/ProHUD/Alert/AlertController.swift index c3047c0..1ea3cbb 100644 --- a/ProHUD/Alert/AlertController.swift +++ b/ProHUD/Alert/AlertController.swift @@ -68,7 +68,7 @@ public extension ProHUD { timeout = 2 } - willLayout() + willLayoutSubviews() } @@ -105,7 +105,7 @@ public extension ProHUD { /// - Parameter timeout: 超时时间 @discardableResult public func timeout(_ timeout: TimeInterval?) -> Alert { self.timeout = timeout - willLayout() + willLayoutSubviews() return self } @@ -132,6 +132,7 @@ public extension ProHUD { self?.remove() } } + willLayoutSubviews() return self } @@ -213,15 +214,16 @@ public extension ProHUD { } fileprivate extension ProHUD.Alert { - func willLayout() { + func willLayoutSubviews() { willLayout?.cancel() + timeoutBlock?.cancel() + showNavButtonsBlock?.cancel() willLayout = DispatchWorkItem(block: { [weak self] in if let a = self { // 布局 alertConfig.loadSubviews(a) alertConfig.updateFrame(a) // 超时 - a.timeoutBlock?.cancel() if let t = a.timeout, t > 0 { a.timeoutBlock = DispatchWorkItem(block: { [weak self] in self?.remove() @@ -232,7 +234,6 @@ fileprivate extension ProHUD.Alert { } // 顶部按钮 if alertConfig.minimizeTimeout > 0 && self?.actionStack.superview == nil { - a.showNavButtonsBlock?.cancel() a.showNavButtonsBlock = DispatchWorkItem(block: { [weak self] in if let s = self { alertConfig.showNavButtons(s) @@ -339,8 +340,7 @@ public extension ProHUD { } // MARK: AlertHUD private func - -fileprivate extension ProHUD { +internal extension ProHUD { func updateAlertsLayout() { for (i, a) in alerts.reversed().enumerated() { @@ -353,6 +353,8 @@ fileprivate extension ProHUD { } } } +} +fileprivate extension ProHUD { func getAlertWindow(_ vc: UIViewController) -> UIWindow { if let w = alertWindow { diff --git a/ProHUD/HUDView.swift b/ProHUD/HUDView.swift index caae496..fc3b095 100644 --- a/ProHUD/HUDView.swift +++ b/ProHUD/HUDView.swift @@ -10,6 +10,29 @@ import UIKit public extension ProHUD { + class ToastWindow: UIWindow { + + var deviceOrientationDidChangeCallback: (() -> Void)? + + public override init(frame: CGRect) { + super.init(frame: frame) + + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + @objc func deviceOrientationDidChange(_ notification: Notification){ + DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { + self.deviceOrientationDidChangeCallback?() + } + } + + } + class StackContainer: UIStackView { diff --git a/ProHUD/ProHUD.swift b/ProHUD/ProHUD.swift index d06797d..ebbc856 100644 --- a/ProHUD/ProHUD.swift +++ b/ProHUD/ProHUD.swift @@ -10,7 +10,7 @@ import UIKit internal let hud = ProHUD.shared -public class ProHUD: NSObject { +public class ProHUD { public static let shared = ProHUD() @@ -19,18 +19,14 @@ public class ProHUD: NSObject { internal var alertWindow: UIWindow? - deinit { - debugPrint(self, "deinit") - } - } internal extension ProHUD { - class var bundle: Bundle { - var b = Bundle.init(for: ProHUD.self) + static var bundle: Bundle { + var b = Bundle.init(for: ProHUD.Alert.self) let p = b.path(forResource: "ProHUD", ofType: "bundle") if let bb = Bundle.init(path: p ?? "") { b = bb @@ -38,7 +34,7 @@ internal extension ProHUD { return b } - class func image(named: String) -> UIImage? { + static func image(named: String) -> UIImage? { return UIImage.init(named: named, in: bundle, compatibleWith: nil) } diff --git a/ProHUD/Toast/ToastConfig.swift b/ProHUD/Toast/ToastConfig.swift index af3e5d4..0ee9a76 100644 --- a/ProHUD/Toast/ToastConfig.swift +++ b/ProHUD/Toast/ToastConfig.swift @@ -84,6 +84,7 @@ public extension ProHUD.Configuration { mk.top.equalToSuperview().offset(config.padding) mk.leading.equalToSuperview().offset(config.padding) mk.bottom.lessThanOrEqualToSuperview().offset(-config.padding) + mk.width.height.equalTo(config.iconSize) } vc.titleLabel.snp.makeConstraints { (mk) in mk.top.equalToSuperview().offset(config.padding) diff --git a/ProHUD/Toast/ToastController.swift b/ProHUD/Toast/ToastController.swift index 6d4df6a..9f9c61c 100644 --- a/ProHUD/Toast/ToastController.swift +++ b/ProHUD/Toast/ToastController.swift @@ -59,6 +59,7 @@ public extension ProHUD { /// 视图模型 public var vm = ViewModel() + public var removable = true internal var tapCallback: (() -> Void)? @@ -262,48 +263,57 @@ fileprivate extension ProHUD.Toast { // MARK: - AlertHUD public func - public extension ProHUD { @discardableResult func show(_ toast: Toast) -> Toast { let config = toastConfig + let isNew: Bool if toast.window == nil { - let width = CGFloat.minimum(UIScreen.main.bounds.width - 2*config.margin, config.maxWidth) - let w = UIWindow(frame: .init(x: (UIScreen.main.bounds.width - width) / 2, y: config.margin, width: width, height: 400)) + let w = ToastWindow(frame: .zero) toast.window = w w.windowLevel = UIWindow.Level(5000) w.backgroundColor = .clear w.layer.shadowRadius = 8 w.layer.shadowOffset = .init(width: 0, height: 5) w.layer.shadowOpacity = 0.2 - w.rootViewController = toast - + w.isHidden = false + isNew = true + } else { + isNew = false } let window = toast.window! - window.isHidden = false - toasts.append(toast) - // background & frame - toast.view.layoutIfNeeded() + // 设定正确的宽度,更新子视图 + let width = CGFloat.minimum(UIScreen.main.bounds.width - 2*config.margin, config.maxWidth) + toast.view.frame.size = CGSize(width: width, height: 800) toast.titleLabel.sizeToFit() toast.bodyLabel.sizeToFit() - let width = toast.view.frame.width + toast.view.layoutIfNeeded() + // 更新子视图之后获取正确的高度 var height = CGFloat(0) for v in toast.view.subviews { height = CGFloat.maximum(v.frame.maxY, height) } height += config.padding - toast.backgroundView.frame.size = CGSize(width: width, height: height) + // 应用到frame + window.frame = CGRect(x: (UIScreen.main.bounds.width - width) / 2, y: 0, width: width, height: height) + toast.backgroundView.frame.size = window.frame.size window.insertSubview(toast.backgroundView, at: 0) - window.frame.size.height = height // 这里之后toast.view.frame.height会变成0 - toast.view.frame.size.height = height - + window.rootViewController = toast // 此时toast.view.frame.size会自动更新为window.frame.size + // 根据在屏幕中的顺序,确定y坐标 + if toasts.contains(toast) == false { + toasts.append(toast) + } updateToastsLayout() - window.transform = .init(translationX: 0, y: -window.frame.maxY) - UIView.animateForToast { - window.transform = .identity + if isNew { + window.transform = .init(translationX: 0, y: -window.frame.maxY) + UIView.animateForToast { + window.transform = .identity + } + } else { + toast.view.layoutIfNeeded() } return toast } @@ -371,33 +381,44 @@ public extension ProHUD { // MARK: AlertHUD private func -fileprivate extension ProHUD { - +fileprivate var willUpdateToastsLayout: DispatchWorkItem? + +internal extension ProHUD { func updateToastsLayout() { - for (i, e) in toasts.enumerated() { - let config = toastConfig - if let window = e.window { - var frame = window.frame - if i == 0 { - if isPortrait { - frame.origin.y = Inspire.shared.screen.updatedSafeAreaInsets.top + func f() { + let top = Inspire.shared.screen.updatedSafeAreaInsets.top + for (i, e) in toasts.enumerated() { + let config = toastConfig + if let window = e.window { + var y = window.frame.origin.y + if i == 0 { + if isPortrait { + y = top + } else { + y = config.margin + } } else { - frame.origin.y = config.margin + let lastY = toasts[i-1].window?.frame.maxY ?? .zero + y = lastY + config.margin + } + UIView.animateForToast { + e.window?.frame.origin.y = y } - } else { - let lastY = toasts[i-1].window?.frame.maxY ?? .zero - frame.origin.y = lastY + config.margin - } - UIView.animateForToast(animations: { - e.window?.frame = frame - }) { (done) in - } } - } + willUpdateToastsLayout?.cancel() + willUpdateToastsLayout = DispatchWorkItem(block: { + f() + }) + DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willUpdateToastsLayout!) } +} + +internal extension ProHUD { + + func removeItemFromArray(toast: Toast) { if toasts.count > 1 { for (i, t) in toasts.enumerated() {