This commit is contained in:
xaoxuu 2019-08-05 11:18:25 +08:00
parent 70a27f58f2
commit ff9805967a
9 changed files with 576 additions and 436 deletions

View File

@ -31,7 +31,7 @@ class ViewController: UIViewController {
let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻") let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻")
let a = ProHUD.push(alert : .loading, title: "正在加载", message: "请稍候片刻") let a = ProHUD.push(alert : .loading, title: "正在加载", message: "请稍候片刻")
a.didMinimize { a.didForceQuit {
hud.push(t) hud.push(t)
} }
t.didTapped { [weak t] in t.didTapped { [weak t] in
@ -58,15 +58,23 @@ class ViewController: UIViewController {
a?.removeAction(index: 0).removeAction(index: 0) a?.removeAction(index: 0).removeAction(index: 0)
a?.updateContent(scene: .loading, title: "正在删除", message: "请稍后片刻") a?.updateContent(scene: .loading, title: "正在删除", message: "请稍后片刻")
DispatchQueue.main.asyncAfter(deadline: .now()+1) { DispatchQueue.main.asyncAfter(deadline: .now()+1) {
a?.updateContent(scene: .success, title: "删除成功", message: "啊哈哈哈哈").timeout(2) a?.updateContent(scene: .success, title: "删除成功", message: "啊哈哈哈哈").duration(2)
ProHUD.show(toast: .success, title: "删除成功", message: "aaa") ProHUD.push(toast: .success, title: "删除成功", message: "aaa")
} }
}).addAction(style: .cancel, title: "取消", action: nil) }).addAction(style: .cancel, title: "取消", action: nil)
} }
@IBAction func test(_ sender: UIButton) { @IBAction func test(_ sender: UIButton) {
textUpdateAction()
}
func testGuard() {
let g = ProHUD.Guard(title: "请求权限", message: "请打开相机权限开关,否则无法进行测量。") let g = ProHUD.Guard(title: "请求权限", message: "请打开相机权限开关,否则无法进行测量。")
g.loadTitle("呵呵") g.loadTitle("呵呵")
g.loadBody("请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。") g.loadBody("请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。")
g.loadButton(style: .default, title: "测试弹窗", action: { [weak self] in g.loadButton(style: .default, title: "测试弹窗", action: { [weak self] in
@ -78,8 +86,18 @@ class ViewController: UIViewController {
g.loadButton(style: .cancel, title: "我知道了") g.loadButton(style: .cancel, title: "我知道了")
g.push(to: self) g.push(to: self)
debugPrint("test: ", g) debugPrint("test: ", g)
}
func textUpdateAction() {
let a = ProHUD.push(alert: .confirm, title: "确认删除", message: "此操作无法撤销")
a.addAction(style: .destructive, title: "删除") {
a.removeAction(index: 0, 1).updateContent(scene: .loading, title: "正在删除", message: "请稍后片刻")
}.addAction(style: .cancel, title: "取消", action: nil)
} }
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

View File

@ -132,7 +132,7 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
isFirstLayout = false isFirstLayout = false
} }
let imgStr: String let imgStr: String
switch vc.vm.scene { switch vc.model.scene {
case .success: case .success:
imgStr = "ProHUDSuccess" imgStr = "ProHUDSuccess"
case .warning: case .warning:
@ -148,7 +148,7 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
default: default:
imgStr = "ProHUDMessage" imgStr = "ProHUDMessage"
} }
let img = vc.vm.icon ?? ProHUD.image(named: imgStr) let img = vc.model.icon ?? ProHUD.image(named: imgStr)
if let imgv = vc.imageView { if let imgv = vc.imageView {
imgv.image = img imgv.image = img
} else { } else {
@ -167,7 +167,7 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
} }
// text // text
if vc.vm.title?.count ?? 0 > 0 || vc.vm.message?.count ?? 0 > 0 { if vc.model.title?.count ?? 0 > 0 || vc.model.message?.count ?? 0 > 0 {
vc.contentStack.addArrangedSubview(vc.textStack) vc.contentStack.addArrangedSubview(vc.textStack)
vc.textStack.snp.makeConstraints { (mk) in vc.textStack.snp.makeConstraints { (mk) in
mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.75) mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.75)
@ -175,19 +175,19 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
mk.leading.greaterThanOrEqualTo(vc.contentView).offset(config.padding*2) mk.leading.greaterThanOrEqualTo(vc.contentView).offset(config.padding*2)
mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2) mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2)
} }
if vc.vm.title?.count ?? 0 > 0 { if vc.model.title?.count ?? 0 > 0 {
if let lb = vc.titleLabel { if let lb = vc.titleLabel {
lb.text = vc.vm.title lb.text = vc.model.title
} else { } else {
let title = UILabel() let title = UILabel()
title.textAlignment = .center title.textAlignment = .center
title.numberOfLines = config.titleMaxLines title.numberOfLines = config.titleMaxLines
title.textColor = cfg.primaryLabelColor title.textColor = cfg.primaryLabelColor
title.text = vc.vm.title title.text = vc.model.title
vc.textStack.addArrangedSubview(title) vc.textStack.addArrangedSubview(title)
vc.titleLabel = title vc.titleLabel = title
} }
if vc.vm.message?.count ?? 0 > 0 { if vc.model.message?.count ?? 0 > 0 {
// message // message
vc.titleLabel?.font = config.titleFont vc.titleLabel?.font = config.titleFont
} else { } else {
@ -197,28 +197,28 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
} else { } else {
vc.titleLabel?.removeFromSuperview() vc.titleLabel?.removeFromSuperview()
} }
if vc.vm.message?.count ?? 0 > 0 { if vc.model.message?.count ?? 0 > 0 {
if let lb = vc.messageLabel { if let lb = vc.bodyLabel {
lb.text = vc.vm.message lb.text = vc.model.message
} else { } else {
let body = UILabel() let body = UILabel()
body.textAlignment = .center body.textAlignment = .center
body.font = config.bodyFont body.font = config.bodyFont
body.numberOfLines = config.bodyMaxLines body.numberOfLines = config.bodyMaxLines
body.textColor = cfg.secondaryLabelColor body.textColor = cfg.secondaryLabelColor
body.text = vc.vm.message body.text = vc.model.message
vc.textStack.addArrangedSubview(body) vc.textStack.addArrangedSubview(body)
vc.messageLabel = body vc.bodyLabel = body
} }
if vc.vm.title?.count ?? 0 > 0 { if vc.model.title?.count ?? 0 > 0 {
// title // title
vc.messageLabel?.font = config.bodyFont vc.bodyLabel?.font = config.bodyFont
} else { } else {
// title // title
vc.messageLabel?.font = config.boldTextFont vc.bodyLabel?.font = config.boldTextFont
} }
} else { } else {
vc.messageLabel?.removeFromSuperview() vc.bodyLabel?.removeFromSuperview()
} }
} else { } else {
vc.textStack.removeFromSuperview() vc.textStack.removeFromSuperview()
@ -297,7 +297,7 @@ fileprivate var privLoadForceQuitButton: (ProHUD.Alert) -> Void = {
} }
vc.addTouchUpAction(for: btn) { [weak vc] in vc.addTouchUpAction(for: btn) { [weak vc] in
debug("点击了隐藏") debug("点击了隐藏")
vc?.minimizeCallback?() vc?.model.forceQuitCallback?()
vc?.pop() vc?.pop()
} }
} }

View File

@ -12,27 +12,34 @@ import SnapKit
public extension ProHUD { public extension ProHUD {
class Alert: HUDController { class Alert: HUDController {
/// ///
public var contentView = BlurView() public var contentView = BlurView()
/// icontextStackactionStack) /// icontextStackactionStack)
internal var contentStack: StackContainer = { public var contentStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.spacing = cfg.alert.margin stack.spacing = cfg.alert.margin
return stack return stack
}() }()
/// ///
internal var textStack: StackContainer = { public var textStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.spacing = cfg.alert.margin stack.spacing = cfg.alert.margin
return stack return stack
}() }()
internal var imageView: UIImageView?
internal var titleLabel: UILabel? ///
internal var messageLabel: UILabel? public var imageView: UIImageView?
///
public var titleLabel: UILabel?
///
public var bodyLabel: UILabel?
/// ///
internal var actionStack: StackContainer = { public var actionStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.alignment = .fill stack.alignment = .fill
stack.spacing = cfg.alert.margin stack.spacing = cfg.alert.margin
@ -40,12 +47,8 @@ public extension ProHUD {
}() }()
/// ///
public var vm = ViewModel() public var model = ViewModel()
///
internal var showNavButtonsBlock: DispatchWorkItem?
internal var minimizeCallback: (() -> Void)?
// MARK: // MARK:
@ -57,15 +60,15 @@ public extension ProHUD {
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil) { public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
self.init() self.init()
view.tintColor = cfg.alert.tintColor view.tintColor = cfg.alert.tintColor
vm.scene = scene model.scene = scene
vm.title = title model.title = title
vm.message = message model.message = message
vm.icon = icon model.icon = icon
switch scene { switch scene {
case .loading: case .loading:
timeout = nil model.duration = nil
default: default:
timeout = 2 model.duration = 2
} }
willLayoutSubviews() willLayoutSubviews()
@ -78,172 +81,312 @@ public extension ProHUD {
} }
///
public func pop() {
let window = hud.getAlertWindow(self)
hud.removeItemFromArray(alert: self)
UIView.animateForAlertBuildOut(animations: {
self.view.alpha = 0
self.view.transform = .init(scaleX: 1.08, y: 1.08)
}) { (done) in
self.view.removeFromSuperview()
self.removeFromParent()
}
// hide window
let count = hud.alerts.count
if count == 0 && hud.alertWindow != nil {
UIView.animateForAlertBuildOut(animations: {
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0)
}) { (done) in
hud.alertWindow = nil
}
}
}
// MARK:
///
/// - Parameter timeout:
@discardableResult public func timeout(_ timeout: TimeInterval?) -> Alert {
self.timeout = timeout
willLayoutSubviews()
return self
}
///
/// - Parameter style:
/// - Parameter text:
/// - Parameter action:
@discardableResult public func addAction(style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> Alert {
if let btn = privAddButton(custom: Button.actionButton(title: title), action: action) as? Button {
btn.update(style: style)
}
return self
}
///
/// - Parameter button:
/// - Parameter action:
@discardableResult public func addAction(custom button: UIButton, action: (() -> Void)?) -> Alert {
privAddButton(custom: button, action: action)
return self
}
///
/// - Parameter callback:
@discardableResult public func didMinimize(_ callback: (() -> Void)?) -> Alert {
minimizeCallback = callback
return self
}
///
/// - Parameter callback:
@discardableResult public func didDisappear(_ callback: (() -> Void)?) -> Alert {
disappearCallback = callback
return self
}
///
/// - Parameter title:
@discardableResult public func updateContent(scene: Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Alert {
vm.title = title
vm.message = message
vm.scene = scene
vm.icon = icon
cfg.alert.reloadData(self)
return self
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult public func updateAction(index: Int, style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> Alert {
return updateAction(index: index, button: { (btn) in
btn.setTitle(title, for: .normal)
if let b = btn as? Button {
b.update(style: style)
}
btn.layoutIfNeeded()
}, action: action)
}
@discardableResult public func updateAction(index: Int, button: (UIButton) -> Void, action: (() -> Void)? = nil) -> Alert {
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
button(btn)
if let ac = action {
addTouchUpAction(for: btn, action: ac)
}
}
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
@discardableResult public func removeAction(index: Int) -> Alert {
if index < 0 {
for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton {
btn.removeFromSuperview()
}
}
} else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.removeFromSuperview()
}
if self.actionStack.arrangedSubviews.count == 0 {
self.actionStack.removeFromSuperview()
}
willLayoutSubviews()
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
} }
} }
// MARK: -
public extension ProHUD.Alert {
// MARK:
///
@discardableResult func push() -> ProHUD.Alert {
return ProHUD.push(self)
}
///
func pop() {
let window = hud.getAlertWindow(self)
hud.removeItemFromArray(alert: self)
UIView.animateForAlertBuildOut(animations: {
self.view.alpha = 0
self.view.transform = .init(scaleX: 1.08, y: 1.08)
}) { (done) in
self.view.removeFromSuperview()
self.removeFromParent()
}
// hide window
let count = hud.alerts.count
if count == 0 && hud.alertWindow != nil {
UIView.animateForAlertBuildOut(animations: {
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0)
}) { (done) in
hud.alertWindow = nil
}
}
}
// MARK:
///
/// - Parameter duration:
@discardableResult func duration(_ duration: TimeInterval?) -> ProHUD.Alert {
model.duration = duration
willLayoutSubviews()
return self
}
///
/// - Parameter style:
/// - Parameter text:
/// - Parameter action:
@discardableResult func addAction(style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> ProHUD.Alert {
if let btn = privAddButton(custom: Button.actionButton(title: title), action: action) as? Button {
btn.update(style: style)
}
return self
}
///
/// - Parameter button:
/// - Parameter action:
@discardableResult func addAction(custom button: UIButton, action: (() -> Void)?) -> ProHUD.Alert {
privAddButton(custom: button, action: action)
return self
}
///
/// - Parameter callback:
@discardableResult func didForceQuit(_ callback: (() -> Void)?) -> ProHUD.Alert {
model.forceQuitCallback = callback
return self
}
///
/// - Parameter callback:
@discardableResult func didDisappear(_ callback: (() -> Void)?) -> ProHUD.Alert {
disappearCallback = callback
return self
}
///
/// - Parameter title:
@discardableResult func updateContent(scene: Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> ProHUD.Alert {
model.title = title
model.message = message
model.scene = scene
model.icon = icon
cfg.alert.reloadData(self)
return self
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func updateAction(index: Int, style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> ProHUD.Alert {
return updateAction(index: index, button: { (btn) in
btn.setTitle(title, for: .normal)
if let b = btn as? Button {
b.update(style: style)
}
btn.layoutIfNeeded()
}, action: action)
}
///
/// - Parameter index:
/// - Parameter button:
/// - Parameter action:
@discardableResult func updateAction(index: Int, button: (UIButton) -> Void, action: (() -> Void)? = nil) -> ProHUD.Alert {
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
button(btn)
if let ac = action {
addTouchUpAction(for: btn, action: ac)
}
}
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
///
/// - Parameter index:
@discardableResult func removeAction(index: Int...) -> ProHUD.Alert {
for (i, idx) in index.enumerated() {
privRemoveAction(index: idx-i)
}
return self
}
}
// MARK: -
public extension ProHUD {
///
/// - Parameter alert:
@discardableResult func push(_ alert: Alert) -> Alert {
let window = getAlertWindow(alert)
window.makeKeyAndVisible()
window.resignKey()
window.addSubview(alert.view)
alert.view.transform = .init(scaleX: 1.2, y: 1.2)
alert.view.alpha = 0
UIView.animateForAlertBuildIn {
alert.view.transform = .identity
alert.view.alpha = 1
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0.6)
}
alerts.append(alert)
updateAlertsLayout()
// setup duration
if let _ = alert.model.duration, alert.model.durationBlock == nil {
alert.duration(alert.model.duration)
}
return alert
}
///
/// - Parameter alert:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
@discardableResult func push(alert scene: Alert.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Alert {
return push(Alert(scene: scene, title: title, message: message, icon: icon))
}
///
/// - Parameter identifier:
func alerts(identifier: String?) -> [Alert] {
var aa = [Alert]()
for a in alerts {
if a.identifier == identifier {
aa.append(a)
}
}
return aa
}
///
/// - Parameter alert:
func pop(alert: Alert) {
for a in alerts {
if a == alert {
a.pop()
}
}
}
///
/// - Parameter identifier:
func pop(alert identifier: String?) {
for a in alerts {
if a.identifier == identifier {
a.pop()
}
}
}
}
// MARK:
public extension ProHUD {
///
/// - Parameter alert:
@discardableResult class func push(_ alert: Alert) -> Alert {
return shared.push(alert)
}
///
/// - Parameter alert:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
@discardableResult class func push(alert: Alert.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Alert {
return shared.push(alert: alert, title: title, message: message, icon: icon)
}
///
/// - Parameter identifier:
class func alert(identifier: String?) -> [Alert] {
return shared.alerts(identifier: identifier)
}
///
/// - Parameter alert:
class func pop(alert: Alert) {
shared.pop(alert: alert)
}
///
/// - Parameter identifier:
class func pop(alert identifier: String?) {
shared.pop(alert: identifier)
}
}
// MARK: -
fileprivate extension ProHUD.Alert { fileprivate extension ProHUD.Alert {
///
/// - Parameter index:
@discardableResult func privRemoveAction(index: Int) -> ProHUD.Alert {
if index < 0 {
for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton {
btn.removeFromSuperview()
}
}
} else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.removeFromSuperview()
}
if self.actionStack.arrangedSubviews.count == 0 {
self.actionStack.removeFromSuperview()
}
willLayoutSubviews()
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
func willLayoutSubviews() { func willLayoutSubviews() {
willLayout?.cancel() willLayout?.cancel()
timeoutBlock?.cancel() model.durationBlock?.cancel()
showNavButtonsBlock?.cancel() model.forceQuitTimerBlock?.cancel()
willLayout = DispatchWorkItem(block: { [weak self] in willLayout = DispatchWorkItem(block: { [weak self] in
if let a = self { if let a = self {
// //
cfg.alert.loadSubviews(a) cfg.alert.loadSubviews(a)
cfg.alert.reloadData(a) cfg.alert.reloadData(a)
// //
if let t = a.timeout, t > 0 { if let t = a.model.duration, t > 0 {
a.timeoutBlock = DispatchWorkItem(block: { [weak self] in a.model.durationBlock = DispatchWorkItem(block: { [weak self] in
self?.pop() self?.pop()
}) })
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: a.timeoutBlock!) DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: a.model.durationBlock!)
} else { } else {
a.timeoutBlock = nil a.model.durationBlock = nil
} }
// // 退
if cfg.alert.forceQuitTimer > 0 && self?.actionStack.superview == nil { if cfg.alert.forceQuitTimer > 0 && self?.actionStack.superview == nil {
a.showNavButtonsBlock = DispatchWorkItem(block: { [weak self] in a.model.forceQuitTimerBlock = DispatchWorkItem(block: { [weak self] in
if let s = self { if let s = self {
cfg.alert.loadForceQuitButton(s) cfg.alert.loadForceQuitButton(s)
} }
}) })
DispatchQueue.main.asyncAfter(deadline: .now()+cfg.alert.forceQuitTimer, execute: a.showNavButtonsBlock!) DispatchQueue.main.asyncAfter(deadline: .now()+cfg.alert.forceQuitTimer, execute: a.model.forceQuitTimerBlock!)
} }
} }
}) })
DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willLayout!) DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willLayout!)
} }
@discardableResult private func privAddButton(custom button: UIButton, action: (() -> Void)?) -> UIButton { @discardableResult func privAddButton(custom button: UIButton, action: (() -> Void)?) -> UIButton {
timeout = nil model.duration = nil
if actionStack.superview == nil { if actionStack.superview == nil {
contentStack.addArrangedSubview(actionStack) contentStack.addArrangedSubview(actionStack)
} }
@ -266,95 +409,6 @@ fileprivate extension ProHUD.Alert {
} }
// MARK: - AlertHUD public func
public extension ProHUD {
@discardableResult
func push(_ alert: Alert) -> Alert {
let window = getAlertWindow(alert)
window.makeKeyAndVisible()
window.resignKey()
window.addSubview(alert.view)
alert.view.transform = .init(scaleX: 1.2, y: 1.2)
alert.view.alpha = 0
UIView.animateForAlertBuildIn {
alert.view.transform = .identity
alert.view.alpha = 1
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0.6)
}
alerts.append(alert)
updateAlertsLayout()
// setup timeout
if let _ = alert.timeout, alert.timeoutBlock == nil {
alert.timeout(alert.timeout)
}
return alert
}
@discardableResult
func push(alert: Alert.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Alert {
return push(Alert(scene: alert, title: title, message: message, icon: icon))
}
func alerts(identifier: String?) -> [Alert] {
var aa = [Alert]()
for a in alerts {
if a.identifier == identifier {
aa.append(a)
}
}
return aa
}
func pop(alert: Alert) {
for a in alerts {
if a == alert {
a.pop()
}
}
}
func pop(alert identifier: String?) {
for a in alerts {
if a.identifier == identifier {
a.pop()
}
}
}
}
// MARK: AlertHUD public class func
public extension ProHUD {
@discardableResult
class func push(_ alert: Alert) -> Alert {
return shared.push(alert)
}
@discardableResult
class func push(alert: Alert.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Alert {
return shared.push(alert: alert, title: title, message: message, icon: icon)
}
class func alert(identifier: String?) -> [Alert] {
return shared.alerts(identifier: identifier)
}
class func pop(alert: Alert) {
shared.pop(alert: alert)
}
class func pop(alert identifier: String?) {
shared.pop(alert: identifier)
}
}
// MARK: AlertHUD private func
internal extension ProHUD { internal extension ProHUD {
func updateAlertsLayout() { func updateAlertsLayout() {
@ -369,6 +423,7 @@ internal extension ProHUD {
} }
} }
} }
fileprivate extension ProHUD { fileprivate extension ProHUD {
func getAlertWindow(_ vc: UIViewController) -> UIWindow { func getAlertWindow(_ vc: UIViewController) -> UIWindow {

View File

@ -66,6 +66,18 @@ public extension ProHUD.Alert {
/// ///
public var icon: UIImage? public var icon: UIImage?
///
internal var duration: TimeInterval?
///
internal var durationBlock: DispatchWorkItem?
///
internal var forceQuitTimerBlock: DispatchWorkItem?
/// 退
internal var forceQuitCallback: (() -> Void)?
public init(title: String? = nil, message: String? = nil, icon: UIImage? = nil) { public init(title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
self.title = title self.title = title
self.message = message self.message = message

View File

@ -9,12 +9,13 @@
import SnapKit import SnapKit
public extension ProHUD { public extension ProHUD {
class Guard: HUDController { class Guard: HUDController {
/// ///
public var contentView = BlurView() public var contentView = BlurView()
/// textStackactionStack) /// textStackactionStack)
public var contentStack: StackContainer = { public var contentStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.spacing = cfg.guard.padding + cfg.guard.margin stack.spacing = cfg.guard.padding + cfg.guard.margin
@ -22,7 +23,7 @@ public extension ProHUD {
return stack return stack
}() }()
/// ///
public var textStack: StackContainer = { public var textStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.spacing = cfg.guard.margin stack.spacing = cfg.guard.margin
@ -30,10 +31,7 @@ public extension ProHUD {
return stack return stack
}() }()
// public var titleLabel: UILabel? ///
// public var bodyLabel: UILabel?
///
public var actionStack: StackContainer = { public var actionStack: StackContainer = {
let stack = StackContainer() let stack = StackContainer()
stack.alignment = .fill stack.alignment = .fill
@ -47,6 +45,7 @@ public extension ProHUD {
private let tag = Int(23905340) private let tag = Int(23905340)
private var displaying = false private var displaying = false
// MARK: // MARK:
/// ///
@ -56,7 +55,7 @@ public extension ProHUD {
/// - Parameter icon: /// - Parameter icon:
public convenience init(title: String? = nil, message: String? = nil) { public convenience init(title: String? = nil, message: String? = nil) {
self.init() self.init()
// view = View()
view.tintColor = cfg.guard.tintColor view.tintColor = cfg.guard.tintColor
if let _ = title { if let _ = title {
loadTitle(title) loadTitle(title)
@ -84,48 +83,58 @@ public extension ProHUD {
debug(self, "deinit") debug(self, "deinit")
} }
public func push(to viewController: UIViewController? = nil) {
if let vc = viewController { }
view.layoutIfNeeded() }
vc.addChild(self)
vc.view.addSubview(view) // MARK: -
view.isUserInteractionEnabled = true
view.snp.makeConstraints { (mk) in public extension ProHUD.Guard {
mk.edges.equalToSuperview()
} // MARK:
if displaying == false {
translateOut() ///
} /// - Parameter viewController:
displaying = true func push(to viewController: UIViewController? = nil) {
UIView.animateForGuard { if let vc = viewController {
self.translateIn() view.layoutIfNeeded()
} vc.addChild(self)
vc.view.addSubview(view)
view.isUserInteractionEnabled = true
view.snp.makeConstraints { (mk) in
mk.edges.equalToSuperview()
}
if displaying == false {
translateOut()
}
displaying = true
UIView.animateForGuard {
self.translateIn()
} }
} }
public func pop() { }
if displaying {
debug("pop") ///
displaying = false func pop() {
view.isUserInteractionEnabled = false if displaying {
self.removeFromParent() debug("pop")
UIView.animateForGuard(animations: { displaying = false
self.translateOut() view.isUserInteractionEnabled = false
}) { (done) in self.removeFromParent()
if self.displaying == false { UIView.animateForGuard(animations: {
self.view.removeFromSuperview() self.translateOut()
} }) { (done) in
if self.displaying == false {
self.view.removeFromSuperview()
} }
} }
} }
} }
}
public extension ProHUD.Guard {
@discardableResult ///
func loadTitle(_ text: String?) -> UILabel { /// - Parameter text:
@discardableResult func loadTitle(_ text: String?) -> UILabel {
let lb = UILabel() let lb = UILabel()
lb.font = cfg.guard.titleFont lb.font = cfg.guard.titleFont
lb.textColor = cfg.primaryLabelColor lb.textColor = cfg.primaryLabelColor
@ -144,8 +153,9 @@ public extension ProHUD.Guard {
return lb return lb
} }
@discardableResult ///
func loadBody(_ text: String?) -> UILabel { /// - Parameter text:
@discardableResult func loadBody(_ text: String?) -> UILabel {
let lb = UILabel() let lb = UILabel()
lb.font = cfg.guard.bodyFont lb.font = cfg.guard.bodyFont
lb.textColor = cfg.secondaryLabelColor lb.textColor = cfg.secondaryLabelColor
@ -156,8 +166,11 @@ public extension ProHUD.Guard {
return lb return lb
} }
@discardableResult ///
func loadButton(style: UIAlertAction.Style, title: String?, action: (() -> Void)? = nil) -> UIButton { /// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func loadButton(style: UIAlertAction.Style, title: String?, action: (() -> Void)? = nil) -> UIButton {
let btn = Button.actionButton(title: title) let btn = Button.actionButton(title: title)
btn.titleLabel?.font = cfg.guard.buttonFont btn.titleLabel?.font = cfg.guard.buttonFont
if actionStack.superview == nil { if actionStack.superview == nil {

View File

@ -14,11 +14,6 @@ public class HUDController: UIViewController {
internal var willLayout: DispatchWorkItem? internal var willLayout: DispatchWorkItem?
///
internal var timeout: TimeInterval?
internal var timeoutBlock: DispatchWorkItem?
/// ///
internal var disappearCallback: (() -> Void)? internal var disappearCallback: (() -> Void)?
internal var buttonEvents = [UIButton:() -> Void]() internal var buttonEvents = [UIButton:() -> Void]()

View File

@ -77,10 +77,10 @@ fileprivate var privReloadData: (ProHUD.Toast) -> Void = {
return { (vc) in return { (vc) in
debug(vc, "reloadData") debug(vc, "reloadData")
let config = cfg.toast let config = cfg.toast
let scene = vc.vm.scene let scene = vc.model.scene
// //
let imgStr: String let imgStr: String
switch vc.vm.scene { switch vc.model.scene {
case .success: case .success:
imgStr = "ProHUDSuccess" imgStr = "ProHUDSuccess"
case .warning: case .warning:
@ -96,12 +96,12 @@ fileprivate var privReloadData: (ProHUD.Toast) -> Void = {
default: default:
imgStr = "ProHUDMessage" imgStr = "ProHUDMessage"
} }
let img = vc.vm.icon ?? ProHUD.image(named: imgStr) let img = vc.model.icon ?? ProHUD.image(named: imgStr)
vc.imageView.image = img vc.imageView.image = img
vc.titleLabel.textColor = cfg.primaryLabelColor vc.titleLabel.textColor = cfg.primaryLabelColor
vc.titleLabel.text = vc.vm.title vc.titleLabel.text = vc.model.title
vc.bodyLabel.textColor = cfg.secondaryLabelColor vc.bodyLabel.textColor = cfg.secondaryLabelColor
vc.bodyLabel.text = vc.vm.message vc.bodyLabel.text = vc.model.message
// //
vc.imageView.snp.makeConstraints { (mk) in vc.imageView.snp.makeConstraints { (mk) in

View File

@ -15,14 +15,14 @@ public extension ProHUD {
public var window: UIWindow? public var window: UIWindow?
/// ///
internal lazy var imageView: UIImageView = { public lazy var imageView: UIImageView = {
let imgv = UIImageView() let imgv = UIImageView()
imgv.contentMode = .scaleAspectFit imgv.contentMode = .scaleAspectFit
return imgv return imgv
}() }()
/// ///
internal lazy var titleLabel: UILabel = { public lazy var titleLabel: UILabel = {
let lb = UILabel() let lb = UILabel()
lb.textColor = cfg.primaryLabelColor lb.textColor = cfg.primaryLabelColor
lb.font = cfg.toast.titleFont lb.font = cfg.toast.titleFont
@ -32,7 +32,7 @@ public extension ProHUD {
}() }()
/// ///
internal lazy var bodyLabel: UILabel = { public lazy var bodyLabel: UILabel = {
let lb = UILabel() let lb = UILabel()
lb.textColor = cfg.secondaryLabelColor lb.textColor = cfg.secondaryLabelColor
lb.font = cfg.toast.bodyFont lb.font = cfg.toast.bodyFont
@ -42,7 +42,7 @@ public extension ProHUD {
}() }()
/// ///
var backgroundView: UIVisualEffectView = { public var backgroundView: UIVisualEffectView = {
let vev = UIVisualEffectView() let vev = UIVisualEffectView()
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
vev.effect = UIBlurEffect.init(style: .systemMaterial) vev.effect = UIBlurEffect.init(style: .systemMaterial)
@ -55,12 +55,7 @@ public extension ProHUD {
}() }()
/// ///
public var vm = ViewModel() public var model = ViewModel()
public var removable = true
internal var tapCallback: (() -> Void)?
// MARK: // MARK:
@ -72,15 +67,15 @@ public extension ProHUD {
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil) { public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
self.init() self.init()
vm.scene = scene model.scene = scene
vm.title = title model.title = title
vm.message = message model.message = message
vm.icon = icon model.icon = icon
switch scene { switch scene {
case .loading: case .loading:
timeout = nil model.duration = nil
default: default:
timeout = 2 model.duration = 2
} }
// //
@ -101,88 +96,103 @@ public extension ProHUD {
disappearCallback?() disappearCallback?()
} }
}
///
public func pop() { }
hud.removeItemFromArray(toast: self)
UIView.animateForToast(animations: { // MARK: -
let frame = self.window?.frame ?? .zero
self.window?.transform = .init(translationX: 0, y: -200-frame.maxY) public extension ProHUD.Toast {
}) { (done) in
self.view.removeFromSuperview() // MARK:
self.removeFromParent()
self.window = nil ///
} func push() {
ProHUD.push(self)
}
///
func pop() {
hud.removeItemFromArray(toast: self)
UIView.animateForToast(animations: {
let frame = self.window?.frame ?? .zero
self.window?.transform = .init(translationX: 0, y: -200-frame.maxY)
}) { (done) in
self.view.removeFromSuperview()
self.removeFromParent()
self.window = nil
} }
}
@discardableResult
func update(title: String?) -> Toast { // MARK:
vm.title = title
titleLabel.text = title ///
return self /// - Parameter duration:
@discardableResult func duration(_ duration: TimeInterval?) -> ProHUD.Toast {
model.duration = duration
//
model.durationBlock?.cancel()
if let t = duration, t > 0 {
model.durationBlock = DispatchWorkItem(block: { [weak self] in
self?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: model.durationBlock!)
} else {
model.durationBlock = nil
} }
return self
@discardableResult }
func update(message: String?) -> Toast {
vm.message = message ///
bodyLabel.text = message /// - Parameter callback:
return self @discardableResult func didTapped(_ callback: (() -> Void)?) -> ProHUD.Toast {
} model.tapCallback = callback
return self
@discardableResult }
func update(icon: UIImage?) -> Toast {
vm.icon = icon ///
imageView.image = icon /// - Parameter callback:
return self @discardableResult func didDisappear(_ callback: (() -> Void)?) -> ProHUD.Toast {
} disappearCallback = callback
return self
}
// MARK:
///
/// /// - Parameter scene:
/// - Parameter timeout: /// - Parameter title:
@discardableResult public func timeout(_ timeout: TimeInterval?) -> Toast { /// - Parameter message:
self.timeout = timeout /// - Parameter icon:
// @discardableResult func update(scene: Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> ProHUD.Toast {
timeoutBlock?.cancel() model.scene = scene
if let t = timeout, t > 0 { model.title = title
timeoutBlock = DispatchWorkItem(block: { [weak self] in model.message = message
self?.pop() model.icon = icon
}) cfg.toast.reloadData(self)
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: timeoutBlock!) return self
} else { }
timeoutBlock = nil
} ///
return self /// - Parameter title:
} @discardableResult func update(title: String?) -> ProHUD.Toast {
model.title = title
/// titleLabel.text = title
/// - Parameter callback: return self
@discardableResult public func didTapped(_ callback: (() -> Void)?) -> Toast { }
tapCallback = callback
return self ///
} /// - Parameter message:
@discardableResult func update(message: String?) -> ProHUD.Toast {
/// model.message = message
/// - Parameter callback: bodyLabel.text = message
@discardableResult public func didDisappear(_ callback: (() -> Void)?) -> Toast { return self
disappearCallback = callback }
return self
} ///
/// - Parameter icon:
/// @discardableResult func update(icon: UIImage?) -> ProHUD.Toast {
/// - Parameter title: model.icon = icon
@discardableResult public func update(scene: Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Toast { imageView.image = icon
vm.scene = scene return self
vm.title = title
vm.message = message
vm.icon = icon
cfg.toast.reloadData(self)
return self
}
} }
} }
@ -192,18 +202,18 @@ fileprivate extension ProHUD.Toast {
/// ///
/// - Parameter sender: /// - Parameter sender:
@objc func privDidTapped(_ sender: UITapGestureRecognizer) { @objc func privDidTapped(_ sender: UITapGestureRecognizer) {
tapCallback?() model.tapCallback?()
} }
/// ///
/// - Parameter sender: /// - Parameter sender:
@objc func privDidPan(_ sender: UIPanGestureRecognizer) { @objc func privDidPan(_ sender: UIPanGestureRecognizer) {
timeoutBlock?.cancel() model.durationBlock?.cancel()
let point = sender.translation(in: sender.view) let point = sender.translation(in: sender.view)
window?.transform = .init(translationX: 0, y: point.y) window?.transform = .init(translationX: 0, y: point.y)
if sender.state == .recognized { if sender.state == .recognized {
let v = sender.velocity(in: sender.view) let v = sender.velocity(in: sender.view)
if removable == true && (((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200) { if model.removable == true && (((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200) {
// //
self.pop() self.pop()
} else { } else {
@ -219,11 +229,13 @@ fileprivate extension ProHUD.Toast {
} }
// MARK: - AlertHUD public func // MARK: -
public extension ProHUD { public extension ProHUD {
@discardableResult /// Toast
func push(_ toast: Toast) -> Toast { /// - Parameter toast:
@discardableResult func push(_ toast: Toast) -> Toast {
let config = cfg.toast let config = cfg.toast
let isNew: Bool let isNew: Bool
if toast.window == nil { if toast.window == nil {
@ -275,11 +287,17 @@ public extension ProHUD {
return toast return toast
} }
@discardableResult /// Toast
func push(toast: Toast.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Toast { /// - Parameter toast:
return push(Toast(scene: toast, title: title, message: message, icon: icon)) /// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
@discardableResult func push(toast scene: Toast.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Toast {
return push(Toast(scene: scene, title: title, message: message, icon: icon))
} }
/// toast
/// - Parameter identifier:
func toasts(identifier: String?) -> [Toast] { func toasts(identifier: String?) -> [Toast] {
var tt = [Toast]() var tt = [Toast]()
for t in toasts { for t in toasts {
@ -290,6 +308,8 @@ public extension ProHUD {
return tt return tt
} }
/// Toast
/// - Parameter toast:
func pop(toast: Toast) { func pop(toast: Toast) {
for t in toasts { for t in toasts {
if t == toast { if t == toast {
@ -298,6 +318,8 @@ public extension ProHUD {
} }
} }
/// Toast
/// - Parameter identifier: Toast
func pop(toast identifier: String?) { func pop(toast identifier: String?) {
for t in toasts { for t in toasts {
if t.identifier == identifier { if t.identifier == identifier {
@ -305,38 +327,50 @@ public extension ProHUD {
} }
} }
} }
} }
// MARK: AlertHUD public class func // MARK:
public extension ProHUD { public extension ProHUD {
@discardableResult /// Toast
class func push(_ toast: Toast) -> Toast { /// - Parameter toast:
@discardableResult class func push(_ toast: Toast) -> Toast {
return shared.push(toast) return shared.push(toast)
} }
@discardableResult /// Toast
class func show(toast: Toast.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Toast { /// - Parameter toast:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
@discardableResult class func push(toast: Toast.Scene, title: String? = nil, message: String? = nil, icon: UIImage? = nil) -> Toast {
return shared.push(toast: toast, title: title, message: message, icon: icon) return shared.push(toast: toast, title: title, message: message, icon: icon)
} }
/// toast
/// - Parameter identifier:
class func toast(identifier: String?) -> [Toast] { class func toast(identifier: String?) -> [Toast] {
return shared.toasts(identifier: identifier) return shared.toasts(identifier: identifier)
} }
/// Toast
/// - Parameter toast:
class func pop(toast: Toast) { class func pop(toast: Toast) {
shared.pop(toast: toast) shared.pop(toast: toast)
} }
/// Toast
/// - Parameter identifier: Toast
class func pop(toast identifier: String?) { class func pop(toast identifier: String?) {
shared.pop(toast: identifier) shared.pop(toast: identifier)
} }
} }
// MARK: AlertHUD private func // MARK:
fileprivate var willUpdateToastsLayout: DispatchWorkItem? fileprivate var willUpdateToastsLayout: DispatchWorkItem?
@ -375,7 +409,8 @@ internal extension ProHUD {
internal extension ProHUD { internal extension ProHUD {
///
/// - Parameter toast:
func removeItemFromArray(toast: Toast) { func removeItemFromArray(toast: Toast) {
if toasts.count > 1 { if toasts.count > 1 {
for (i, t) in toasts.enumerated() { for (i, t) in toasts.enumerated() {

View File

@ -45,6 +45,18 @@ public extension ProHUD.Toast {
/// ///
public var icon: UIImage? public var icon: UIImage?
///
internal var duration: TimeInterval?
///
internal var durationBlock: DispatchWorkItem?
///
public var removable = true
///
internal var tapCallback: (() -> Void)?
public init(title: String? = nil, message: String? = nil, icon: UIImage? = nil) { public init(title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
self.title = title self.title = title
self.message = message self.message = message