This commit is contained in:
xaoxuu 2019-08-12 15:02:36 +08:00
parent 26d7aa0049
commit ca6c36650b
17 changed files with 608 additions and 641 deletions

View File

@ -22,8 +22,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true return true
} }

View File

@ -17,6 +17,8 @@ class ViewController: UIViewController {
ProHUD.config { (cfg) in ProHUD.config { (cfg) in
cfg.rootViewController = self
cfg.alert { (a) in cfg.alert { (a) in
a.duration = 1 a.duration = 1
a.forceQuitTimer = 3 a.forceQuitTimer = 3
@ -29,7 +31,11 @@ class ViewController: UIViewController {
} }
cfg.toast { (t) in cfg.toast { (t) in
// t.iconSize = .init(width: 300, height: 30) // t.iconSize = .init(width: 30, height: 30)
// t.iconForScene { (scene) -> UIImage? in
// return UIImage(named: "icon_download")
// }
} }
} }
@ -51,6 +57,7 @@ class ViewController: UIViewController {
} }
a.update { (vm) in a.update { (vm) in
vm.add(action: .default, title: "OK", handler: nil) vm.add(action: .default, title: "OK", handler: nil)
} }
// a.update() // a.update()
// Alert.push(scene: .loading, title: "Loading") { (a) in // Alert.push(scene: .loading, title: "Loading") { (a) in
@ -127,67 +134,107 @@ class ViewController: UIViewController {
} }
func testToast() { func testToast() {
let t = Toast(scene: .loading, title: "正在加载", message: "请稍候片刻") func f() {
Toast.push { (vm) in
let a = Alert.push(scene : .loading, title: "正在加载", message: "请稍候片刻") vm.scene = .error
a.didForceQuit { vm.title = "正在加载"
t.push() // vm.duration = 1
} vm.message = "请稍候片刻"
t.didTapped { [weak t] in
t?.pop()
Alert.push(scene: .loading, title: "正在加载", message: "马上就要成功了")
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
Alert.push(scene: .error, title: "加载失败", message: "点击充实") { (vm) in
vm.duration = 0
vm.identifier = "hehe"
let a = vm.vc!
vm.add(action: .default, title: "重新加载") {
a.vm.scene = .success
a.vm.title = "加载成功"
a.vm.message = "马上就要成功了aaaa"
a.vm.remove(action: 1, 2)
a.vm.update(action: 0, style: .default, title: "OK") { [weak a] in
a?.pop()
}
}
vm.add(action: .destructive, title: "终止", handler: nil)
vm.add(action: .cancel, title: "取消", handler: nil)
}
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
if let a = Alert.alerts("hehe").last {
a.update { (vm) in
vm.add(action: .cancel, title: "CANCEL", handler: nil)
}
}
}
}.didTapped {
debugPrint("didTapped")
}.didDisappear {
debugPrint("didDisappear")
} }
} }
f()
// let t = Toast(scene: .loading, title: "", message: "")
// let a = Alert.push(scene : .loading, title: "", message: "")
// a.didForceQuit {
// t.push()
// }
//
// t.didTapped { [weak t] in
// t?.pop()
// Alert.push(scene: .loading, title: "", message: "")
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// Alert.push(scene: .error, title: "", message: "") { (vm) in
// vm.duration = 0
// vm.identifier = "hehe"
// let a = vm.vc!
// vm.add(action: .default, title: "") {
// a.vm.scene = .success
// a.vm.title = ""
// a.vm.message = "aaaa"
// a.vm.remove(action: 1, 2)
// a.vm.update(action: 0, style: .default, title: "OK") { [weak a] in
// a?.pop()
// }
//
// }
// vm.add(action: .destructive, title: "", handler: nil)
// vm.add(action: .cancel, title: "", handler: nil)
// }
//
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// if let a = Alert.alerts("hehe").last {
// a.update { (vm) in
// vm.add(action: .cancel, title: "CANCEL", handler: nil)
// }
//
// }
// }
//
//
// }
//
// }
} }
func testGuard() { func testGuard() {
let g = ProHUD.Guard(title: "请求权限", message: "请打开相机权限开关,否则无法进行测量。") Guard.push { (vm) in
vm.add(title: "大标题")
vm.add(subTitle: "副标题")
vm.add(message: "请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。")
vm.add(action: .default, title: "OK") { [weak vm] in
vm?.insert(action: 0, style: .destructive, title: "Del") { [weak vm] in
vm?.update(action: 0, style: .destructive, title: "Delete") {
vm?.remove(action: 0)
}
}
}
vm.insert(action: 0, style: .destructive, title: "Del") { [weak vm] in
g.add(title: "呵呵") vm?.update(action: 0, style: .destructive, title: "Delete") {
g.add(message: "请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。") vm?.remove(action: 0)
g.add(action: .default, title: "测试弹窗", handler: { [weak self] in }
self?.testToast() }
}) vm.add(action: .cancel, title: "Cancel") {
g.add(action: .destructive, title: "测试删除弹窗", handler: { [weak self] in
self?.testDelete()
})
g.add(action: .cancel, title: "我知道了", handler: nil)
g.push(to: self) }
debugPrint("test: ", g)
}
// let g = ProHUD.Guard(title: "", message: "")
//
// g.add(title: "")
// g.add(message: "")
// g.add(action: .default, title: "", handler: { [weak self] in
// self?.testToast()
// })
// g.add(action: .destructive, title: "", handler: { [weak self] in
// self?.testDelete()
// })
// g.add(action: .cancel, title: "", handler: nil)
//
// g.push(to: self)
// debugPrint("test: ", g)
} }
func testUpdateAction() { func testUpdateAction() {

View File

@ -10,16 +10,13 @@
1AE9C44ABAF3F797A5518CE8 /* Pods_ProHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2011798511AD590A613E54E /* Pods_ProHUD.framework */; }; 1AE9C44ABAF3F797A5518CE8 /* Pods_ProHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2011798511AD590A613E54E /* Pods_ProHUD.framework */; };
CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490A22EF09AB0077988C /* AlertModel.swift */; }; CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490A22EF09AB0077988C /* AlertModel.swift */; };
CD16490D22EF09B40077988C /* AlertConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490C22EF09B40077988C /* AlertConfig.swift */; }; CD16490D22EF09B40077988C /* AlertConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490C22EF09B40077988C /* AlertConfig.swift */; };
CD16490F22EF09D50077988C /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490E22EF09D50077988C /* AlertView.swift */; };
CD16491222EF0D900077988C /* HUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16491122EF0D900077988C /* HUDView.swift */; }; CD16491222EF0D900077988C /* HUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16491122EF0D900077988C /* HUDView.swift */; };
CD16491422EF12220077988C /* ProHUD.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD16491322EF12220077988C /* ProHUD.xcassets */; }; CD16491422EF12220077988C /* ProHUD.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD16491322EF12220077988C /* ProHUD.xcassets */; };
CD6CD86C22F1858F00F4FD4A /* ToastModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */; }; CD6CD86C22F1858F00F4FD4A /* ToastModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */; };
CD6CD86E22F185A000F4FD4A /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86D22F185A000F4FD4A /* ToastView.swift */; };
CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86F22F185A700F4FD4A /* ToastController.swift */; }; CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86F22F185A700F4FD4A /* ToastController.swift */; };
CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */; }; CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */; };
CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87422F185C200F4FD4A /* GuardController.swift */; }; CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87422F185C200F4FD4A /* GuardController.swift */; };
CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87822F185D000F4FD4A /* GuardConfig.swift */; }; CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87822F185D000F4FD4A /* GuardConfig.swift */; };
CD6CD87B22F185D600F4FD4A /* GuardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87A22F185D600F4FD4A /* GuardView.swift */; };
CD95D22122E72C4C007559A3 /* ProHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = CD95D21F22E72C4C007559A3 /* ProHUD.h */; settings = {ATTRIBUTES = (Public, ); }; }; CD95D22122E72C4C007559A3 /* ProHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = CD95D21F22E72C4C007559A3 /* ProHUD.h */; settings = {ATTRIBUTES = (Public, ); }; };
CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26822E72DA1007559A3 /* AlertController.swift */; }; CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26822E72DA1007559A3 /* AlertController.swift */; };
CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26A22E72DB3007559A3 /* ProHUD.swift */; }; CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26A22E72DB3007559A3 /* ProHUD.swift */; };
@ -33,16 +30,13 @@
C2011798511AD590A613E54E /* Pods_ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C2011798511AD590A613E54E /* Pods_ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CD16490A22EF09AB0077988C /* AlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = "<group>"; }; CD16490A22EF09AB0077988C /* AlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = "<group>"; };
CD16490C22EF09B40077988C /* AlertConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertConfig.swift; sourceTree = "<group>"; }; CD16490C22EF09B40077988C /* AlertConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertConfig.swift; sourceTree = "<group>"; };
CD16490E22EF09D50077988C /* AlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertView.swift; sourceTree = "<group>"; };
CD16491122EF0D900077988C /* HUDView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDView.swift; sourceTree = "<group>"; }; CD16491122EF0D900077988C /* HUDView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDView.swift; sourceTree = "<group>"; };
CD16491322EF12220077988C /* ProHUD.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ProHUD.xcassets; sourceTree = "<group>"; }; CD16491322EF12220077988C /* ProHUD.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ProHUD.xcassets; sourceTree = "<group>"; };
CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastModel.swift; sourceTree = "<group>"; }; CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastModel.swift; sourceTree = "<group>"; };
CD6CD86D22F185A000F4FD4A /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
CD6CD86F22F185A700F4FD4A /* ToastController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastController.swift; sourceTree = "<group>"; }; CD6CD86F22F185A700F4FD4A /* ToastController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastController.swift; sourceTree = "<group>"; };
CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfig.swift; sourceTree = "<group>"; }; CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfig.swift; sourceTree = "<group>"; };
CD6CD87422F185C200F4FD4A /* GuardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardController.swift; sourceTree = "<group>"; }; CD6CD87422F185C200F4FD4A /* GuardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardController.swift; sourceTree = "<group>"; };
CD6CD87822F185D000F4FD4A /* GuardConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardConfig.swift; sourceTree = "<group>"; }; CD6CD87822F185D000F4FD4A /* GuardConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardConfig.swift; sourceTree = "<group>"; };
CD6CD87A22F185D600F4FD4A /* GuardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardView.swift; sourceTree = "<group>"; };
CD95D21C22E72C4C007559A3 /* ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CD95D21C22E72C4C007559A3 /* ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CD95D21F22E72C4C007559A3 /* ProHUD.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProHUD.h; sourceTree = "<group>"; }; CD95D21F22E72C4C007559A3 /* ProHUD.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProHUD.h; sourceTree = "<group>"; };
CD95D22022E72C4C007559A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; CD95D22022E72C4C007559A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -90,7 +84,6 @@
CD95D26822E72DA1007559A3 /* AlertController.swift */, CD95D26822E72DA1007559A3 /* AlertController.swift */,
CD16490A22EF09AB0077988C /* AlertModel.swift */, CD16490A22EF09AB0077988C /* AlertModel.swift */,
CD16490C22EF09B40077988C /* AlertConfig.swift */, CD16490C22EF09B40077988C /* AlertConfig.swift */,
CD16490E22EF09D50077988C /* AlertView.swift */,
); );
path = Alert; path = Alert;
sourceTree = "<group>"; sourceTree = "<group>";
@ -99,7 +92,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */, CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */,
CD6CD86D22F185A000F4FD4A /* ToastView.swift */,
CD6CD86F22F185A700F4FD4A /* ToastController.swift */, CD6CD86F22F185A700F4FD4A /* ToastController.swift */,
CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */, CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */,
); );
@ -111,7 +103,6 @@
children = ( children = (
CD6CD87422F185C200F4FD4A /* GuardController.swift */, CD6CD87422F185C200F4FD4A /* GuardController.swift */,
CD6CD87822F185D000F4FD4A /* GuardConfig.swift */, CD6CD87822F185D000F4FD4A /* GuardConfig.swift */,
CD6CD87A22F185D600F4FD4A /* GuardView.swift */,
CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */, CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */,
); );
path = Guard; path = Guard;
@ -280,12 +271,9 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CD6CD87B22F185D600F4FD4A /* GuardView.swift in Sources */,
CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */, CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */,
CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */, CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */,
CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */, CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */,
CD16490F22EF09D50077988C /* AlertView.swift in Sources */,
CD6CD86E22F185A000F4FD4A /* ToastView.swift in Sources */,
CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */, CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */,
CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */, CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */,
CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */, CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */,

View File

@ -22,12 +22,14 @@ public extension ProHUD.Configuration {
/// ///
public var padding = CGFloat(16) public var padding = CGFloat(16)
// MARK: ///
/// default
public var tintColor: UIColor? public var tintColor: UIColor?
// MARK:
/// ///
public var iconSize = CGSize(width: 48, height: 48) public var iconSize = CGSize(width: 48, height: 48)
///
/// - Parameter callback:
public func iconForScene(_ callback: @escaping (ProHUD.Alert.Scene) -> UIImage?) { public func iconForScene(_ callback: @escaping (ProHUD.Alert.Scene) -> UIImage?) {
privIconForScene = callback privIconForScene = callback
} }
@ -38,7 +40,7 @@ public extension ProHUD.Configuration {
/// ///
public var titleMaxLines = Int(1) public var titleMaxLines = Int(1)
/// ///
public var boldTextFont = UIFont.boldSystemFont(ofSize: 18) public var boldTextFont = UIFont.boldSystemFont(ofSize: 18)
/// ///
@ -78,7 +80,6 @@ public extension ProHUD.Configuration {
// MARK: - // MARK: -
internal extension ProHUD.Configuration.Alert { internal extension ProHUD.Configuration.Alert {
var reloadData: (ProHUD.Alert) -> Void { var reloadData: (ProHUD.Alert) -> Void {
return privReloadData return privReloadData
@ -87,7 +88,6 @@ internal extension ProHUD.Configuration.Alert {
// MARK: - // MARK: -
fileprivate var privLayoutContentView: (ProHUD.Alert) -> Void = { fileprivate var privLayoutContentView: (ProHUD.Alert) -> Void = {
return { (vc) in return { (vc) in
if vc.contentView.superview == nil { if vc.contentView.superview == nil {
@ -263,7 +263,7 @@ fileprivate var privLoadForceQuitButton: (ProHUD.Alert) -> Void = {
let config = cfg.alert let config = cfg.alert
let btn = ProHUD.Alert.Button.forceQuitButton() let btn = ProHUD.Alert.Button.forceQuitButton()
btn.setTitle(cfg.alert.forceQuitTitle, for: .normal) btn.setTitle(cfg.alert.forceQuitTitle, for: .normal)
let bg = ProHUD.BlurView() let bg = createBlurView()
bg.layer.masksToBounds = true bg.layer.masksToBounds = true
bg.layer.cornerRadius = config.cornerRadius bg.layer.cornerRadius = config.cornerRadius
if let last = vc.view.subviews.last { if let last = vc.view.subviews.last {

View File

@ -19,7 +19,7 @@ public extension ProHUD {
internal static var alertWindow: UIWindow? internal static var alertWindow: UIWindow?
/// ///
public var contentView = BlurView() public var contentView = createBlurView()
/// icontextStackactionStack) /// icontextStackactionStack)
public var contentStack: StackContainer = { public var contentStack: StackContainer = {
@ -88,12 +88,10 @@ public extension ProHUD {
public extension Alert { public extension Alert {
// MARK:
/// ///
@discardableResult func push() -> Alert { @discardableResult func push() -> Alert {
if Alert.alerts.contains(self) == false { if Alert.alerts.contains(self) == false {
let window = Alert.getAlertWindow(self) let window = Alert.privGetAlertWindow(self)
window.makeKeyAndVisible() window.makeKeyAndVisible()
window.resignKey() window.resignKey()
window.addSubview(view) window.addSubview(view)
@ -106,14 +104,14 @@ public extension Alert {
} }
Alert.alerts.append(self) Alert.alerts.append(self)
} }
Alert.updateAlertsLayout() Alert.privUpdateAlertsLayout()
return self return self
} }
/// ///
func pop() { func pop() {
let window = Alert.getAlertWindow(self) let window = Alert.privGetAlertWindow(self)
Alert.removeItemFromArray(alert: self) Alert.privRemoveItemFromArray(alert: self)
UIView.animateForAlertBuildOut(animations: { UIView.animateForAlertBuildOut(animations: {
self.view.alpha = 0 self.view.alpha = 0
self.view.transform = .init(scaleX: 1.08, y: 1.08) self.view.transform = .init(scaleX: 1.08, y: 1.08)
@ -132,29 +130,24 @@ public extension Alert {
} }
} }
///
// MARK: /// - Parameter callback:
func update(_ callback: ((inout ViewModel) -> Void)? = nil) {
callback?(&vm)
cfg.alert.reloadData(self)
}
/// ///
/// - Parameter callback: /// - Parameter callback:
@discardableResult func didForceQuit(_ callback: (() -> Void)?) -> Alert { func didForceQuit(_ callback: (() -> Void)?) {
vm.forceQuitCallback = callback vm.forceQuitCallback = callback
return self
} }
/// ///
/// - Parameter callback: /// - Parameter callback:
@discardableResult func didDisappear(_ callback: (() -> Void)?) -> Alert { func didDisappear(_ callback: (() -> Void)?) {
disappearCallback = callback disappearCallback = callback
return self
}
///
/// - Parameter callback:
func update(_ callback: ((inout Alert.ViewModel) -> Void)? = nil) {
callback?(&vm)
cfg.alert.reloadData(self)
} }
func animate(rotate: Bool) { func animate(rotate: Bool) {
@ -177,8 +170,7 @@ public extension Alert {
} }
// MARK: // MARK: -
public extension Alert { public extension Alert {
/// ///
@ -186,7 +178,7 @@ public extension Alert {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter actions: /// - Parameter actions:
@discardableResult class func push(scene: Alert.Scene, title: String? = nil, message: String? = nil, actions: ((inout Alert.ViewModel) -> Void)? = nil) -> Alert { @discardableResult class func push(scene: Alert.Scene = .default, title: String? = nil, message: String? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Alert {
return Alert(scene: scene, title: title, message: message, actions: actions).push() return Alert(scene: scene, title: title, message: message, actions: actions).push()
} }
@ -218,45 +210,30 @@ public extension Alert {
} }
// MARK: -
// MARK: -
internal extension Alert { internal extension Alert {
///
/// - Parameter index:
@discardableResult func privRemoveAction(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()
}
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
@discardableResult func privAddButton(custom button: UIButton, at index: Int? = nil, handler: (() -> Void)?) -> UIButton { ///
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func insert(action index: Int?, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
let btn = Button.actionButton(title: title)
if let idx = index, idx < actionStack.arrangedSubviews.count {
actionStack.insertArrangedSubview(btn, at: idx)
} else {
actionStack.addArrangedSubview(btn)
}
btn.update(style: style)
if actionStack.superview == nil { if actionStack.superview == nil {
contentStack.addArrangedSubview(actionStack) contentStack.addArrangedSubview(actionStack)
contentStack.layoutIfNeeded() contentStack.layoutIfNeeded()
} }
if let idx = index, idx < actionStack.arrangedSubviews.count { addTouchUpAction(for: btn) { [weak self] in
actionStack.insertArrangedSubview(button, at: idx)
} else {
actionStack.addArrangedSubview(button)
}
addTouchUpAction(for: button) { [weak self] in
handler?() handler?()
if button.tag == UIAlertAction.Style.cancel.rawValue { if btn.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop() self?.pop()
} }
} }
@ -266,10 +243,10 @@ internal extension Alert {
self.view.layoutIfNeeded() self.view.layoutIfNeeded()
} }
} }
return button return btn
} }
func privUpdateButton(action index: Int, style: UIAlertAction.Style, title: String?, _ handler: (() -> Void)?) { func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton { if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.setTitle(title, for: .normal) btn.setTitle(title, for: .normal)
if let b = btn as? Button { if let b = btn as? Button {
@ -287,10 +264,30 @@ internal extension Alert {
} }
} }
///
/// - Parameter index:
@discardableResult func remove(action 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()
}
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
} }
fileprivate extension Alert { fileprivate extension Alert {
class func updateAlertsLayout() { class func privUpdateAlertsLayout() {
for (i, a) in alerts.reversed().enumerated() { for (i, a) in alerts.reversed().enumerated() {
let scale = CGFloat(pow(0.7, CGFloat(i))) let scale = CGFloat(pow(0.7, 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: {
@ -301,7 +298,7 @@ fileprivate extension Alert {
} }
} }
} }
class func getAlertWindow(_ vc: UIViewController) -> UIWindow { class func privGetAlertWindow(_ vc: UIViewController) -> UIWindow {
if let w = alertWindow { if let w = alertWindow {
return w return w
} }
@ -313,7 +310,7 @@ fileprivate extension Alert {
return w return w
} }
class func removeItemFromArray(alert: Alert) { class func privRemoveItemFromArray(alert: Alert) {
if alerts.count > 1 { if alerts.count > 1 {
for (i, a) in alerts.enumerated() { for (i, a) in alerts.enumerated() {
if a == alert { if a == alert {
@ -322,7 +319,7 @@ fileprivate extension Alert {
} }
} }
} }
updateAlertsLayout() privUpdateAlertsLayout()
} else if alerts.count == 1 { } else if alerts.count == 1 {
alerts.removeAll() alerts.removeAll()
} else { } else {

View File

@ -33,7 +33,7 @@ public extension Alert {
} }
struct ViewModel { class ViewModel {
/// ID /// ID
public var identifier = String(Date().timeIntervalSince1970) public var identifier = String(Date().timeIntervalSince1970)
@ -67,9 +67,8 @@ public extension Alert {
didSet { didSet {
durationBlock?.cancel() durationBlock?.cancel()
if let t = duration, t > 0 { if let t = duration, t > 0 {
let v = vc durationBlock = DispatchWorkItem(block: { [weak self] in
durationBlock = DispatchWorkItem(block: { self?.vc?.pop()
v?.pop()
}) })
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!) DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else { } else {
@ -80,6 +79,8 @@ public extension Alert {
public weak var vc: Alert? public weak var vc: Alert?
// MARK:
/// ///
internal var durationBlock: DispatchWorkItem? internal var durationBlock: DispatchWorkItem?
@ -99,13 +100,9 @@ public extension Alert.ViewModel {
/// - Parameter style: /// - Parameter style:
/// - Parameter text: /// - Parameter text:
/// - Parameter handler: /// - Parameter handler:
@discardableResult mutating func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { @discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
duration = 0 duration = 0
let btn = vc?.privAddButton(custom: Alert.Button.actionButton(title: title), handler: handler) return vc!.insert(action: nil, style: style, title: title, handler: handler)
if let b = btn as? Alert.Button {
b.update(style: style)
}
return btn!
} }
/// ///
@ -113,13 +110,9 @@ public extension Alert.ViewModel {
/// - Parameter style: /// - Parameter style:
/// - Parameter title: /// - Parameter title:
/// - Parameter handler: /// - Parameter handler:
@discardableResult mutating func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { @discardableResult func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
duration = 0 duration = 0
let btn = vc?.privAddButton(custom: Alert.Button.actionButton(title: title), at: index, handler: handler) return vc!.insert(action: index, style: style, title: title, handler: handler)
if let b = btn as? Alert.Button {
b.update(style: style)
}
return btn!
} }
/// ///
@ -127,16 +120,15 @@ public extension Alert.ViewModel {
/// - Parameter style: /// - Parameter style:
/// - Parameter title: /// - Parameter title:
/// - Parameter handler: /// - Parameter handler:
mutating func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
vc?.privUpdateButton(action: index, style: style, title: title, handler) vc?.update(action: index, style: style, title: title, handler: handler)
} }
/// ///
/// - Parameter index: /// - Parameter index:
mutating func remove(action index: Int...) { func remove(action index: Int...) {
guard let alert = self.vc else { return }
for (i, idx) in index.enumerated() { for (i, idx) in index.enumerated() {
alert.privRemoveAction(index: idx-i) vc?.remove(action: idx-i)
} }
} }

View File

@ -1,55 +0,0 @@
//
// AlertView.swift
// ProHUD
//
// Created by xaoxuu on 2019/7/29.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
internal extension Alert {
class Button: UIButton {
class func actionButton(title: String?) -> UIButton {
let btn = Button(type: .system)
btn.setTitle(title, for: .normal)
btn.layer.cornerRadius = cfg.alert.cornerRadius / 2
btn.titleLabel?.font = cfg.alert.buttonFont
return btn
}
func update(style: UIAlertAction.Style) {
let pd = CGFloat(8)
if style != .cancel {
backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04)
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
} else {
backgroundColor = .clear
contentEdgeInsets = .init(top: pd*0.5, left: pd*1.5, bottom: pd*0.5, right: pd*1.5)
}
switch style {
case .default:
setTitleColor(tintColor, for: .normal)
case .destructive:
setTitleColor(.init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1), for: .normal)
case .cancel:
setTitleColor(cfg.secondaryLabelColor, for: .normal)
@unknown default:
break
}
tag = style.rawValue
}
class func forceQuitButton() -> UIButton {
let btn = Button(type: .system)
let pd = cfg.alert.padding/2
btn.contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
btn.imageEdgeInsets.right = pd*1.5
btn.setTitleColor(UIColor(red:1.00, green:0.55, blue:0.21, alpha:1.00), for: .normal)
btn.titleLabel?.font = cfg.alert.buttonFont
return btn
}
}
}

View File

@ -22,7 +22,6 @@ public extension ProHUD.Configuration {
/// ///
public var padding = CGFloat(16) public var padding = CGFloat(16)
// MARK:
/// ///
public var tintColor: UIColor? public var tintColor: UIColor?
@ -41,12 +40,6 @@ public extension ProHUD.Configuration {
/// ///
public var buttonCornerRadius = CGFloat(12) public var buttonCornerRadius = CGFloat(12)
///
/// - Parameter callback:
public mutating func loadSubviews(_ callback: @escaping (ProHUD.Guard) -> Void) {
privLoadSubviews = callback
}
/// ///
/// - Parameter callback: /// - Parameter callback:
public mutating func reloadData(_ callback: @escaping (ProHUD.Guard) -> Void) { public mutating func reloadData(_ callback: @escaping (ProHUD.Guard) -> Void) {
@ -56,15 +49,14 @@ public extension ProHUD.Configuration {
} }
} }
// MARK: -
// MARK: -
internal extension ProHUD.Configuration.Guard { internal extension ProHUD.Configuration.Guard {
var loadSubviews: (ProHUD.Guard) -> Void {
return privLoadSubviews
}
var reloadData: (ProHUD.Guard) -> Void { var reloadData: (ProHUD.Guard) -> Void {
return privReloadData return privReloadData
} }
var reloadStack: (ProHUD.Guard) -> Void { var reloadStack: (ProHUD.Guard) -> Void {
return { (vc) in return { (vc) in
if vc.textStack.arrangedSubviews.count > 0 { if vc.textStack.arrangedSubviews.count > 0 {
@ -82,14 +74,7 @@ internal extension ProHUD.Configuration.Guard {
} }
fileprivate var privLoadSubviews: (ProHUD.Guard) -> Void = { // MARK: -
return { (vc) in
debug(vc, "loadSubviews")
let config = cfg.guard
}
}()
fileprivate var privReloadData: (ProHUD.Guard) -> Void = { fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
return { (vc) in return { (vc) in
debug(vc, "reloadData") debug(vc, "reloadData")
@ -114,10 +99,10 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
vc.contentView.snp.makeConstraints { (mk) in vc.contentView.snp.makeConstraints { (mk) in
mk.centerX.equalToSuperview() mk.centerX.equalToSuperview()
if UIDevice.current.userInterfaceIdiom == .phone { if UIDevice.current.userInterfaceIdiom == .phone {
if width == config.cardMaxWidth { if width < config.cardMaxWidth {
mk.bottom.equalToSuperview().offset(-Inspire.shared.screen.safeAreaInsets.bottom)
} else {
mk.bottom.equalToSuperview() mk.bottom.equalToSuperview()
} else {
mk.bottom.equalToSuperview().offset(-Inspire.shared.screen.safeAreaInsets.bottom)
} }
} else if UIDevice.current.userInterfaceIdiom == .pad { } else if UIDevice.current.userInterfaceIdiom == .pad {
mk.centerY.equalToSuperview() mk.centerY.equalToSuperview()
@ -126,12 +111,17 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
} }
// stack // stack
vc.contentStack.snp.makeConstraints { (mk) in vc.contentStack.snp.makeConstraints { (mk) in
mk.top.equalToSuperview().offset(config.padding + config.margin) mk.top.equalToSuperview().offset(config.padding)
mk.centerX.equalToSuperview() mk.centerX.equalToSuperview()
if width == config.cardMaxWidth { if width < config.cardMaxWidth {
mk.bottom.equalToSuperview().offset(-config.padding) let bottom = Inspire.shared.screen.safeAreaInsets.bottom
if bottom == 0 {
mk.bottom.equalToSuperview().offset(-config.padding)
} else {
mk.bottom.equalToSuperview().offset(-config.padding/2 - bottom)
}
} else { } else {
mk.bottom.equalToSuperview().offset(-config.padding-Inspire.shared.screen.safeAreaInsets.bottom) mk.bottom.equalToSuperview().offset(-config.padding)
} }
if isPortrait { if isPortrait {
mk.width.equalToSuperview().offset(-config.padding * 2) mk.width.equalToSuperview().offset(-config.padding * 2)
@ -139,6 +129,6 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
mk.width.equalToSuperview().offset(-config.padding * 4) mk.width.equalToSuperview().offset(-config.padding * 4)
} }
} }
config.reloadStack(vc)
} }
}() }()

View File

@ -15,7 +15,7 @@ public extension ProHUD {
class Guard: HUDController { class Guard: HUDController {
/// ///
public var contentView = BlurView() public var contentView = createBlurView()
/// textStackactionStack) /// textStackactionStack)
public var contentStack: StackContainer = { public var contentStack: StackContainer = {
@ -53,6 +53,7 @@ public extension ProHUD {
public var vm = ViewModel() public var vm = ViewModel()
// MARK: // MARK:
internal var isLoadFinished = false
/// ///
/// - Parameter title: /// - Parameter title:
@ -69,29 +70,27 @@ public extension ProHUD {
} }
actions?(&vm) actions?(&vm)
view.tintColor = cfg.guard.tintColor
cfg.guard.loadSubviews(self)
cfg.guard.reloadData(self)
cfg.guard.reloadStack(self)
// //
let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:))) let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:)))
view.addGestureRecognizer(tap) view.addGestureRecognizer(tap)
} }
public override func viewDidLoad() {
super.viewDidLoad()
view.tintColor = cfg.guard.tintColor
cfg.guard.reloadData(self)
isLoadFinished = true
}
} }
} }
// MARK: - // MARK: -
public extension Guard { public extension Guard {
// MARK:
/// ///
/// - Parameter viewController: /// - Parameter viewController:
@discardableResult func push(to viewController: UIViewController? = nil) -> Guard { @discardableResult func push(to viewController: UIViewController? = nil) -> Guard {
@ -104,11 +103,11 @@ public extension Guard {
mk.edges.equalToSuperview() mk.edges.equalToSuperview()
} }
if displaying == false { if displaying == false {
translateOut() privTranslateOut()
} }
displaying = true displaying = true
UIView.animateForGuard { UIView.animateForGuard {
self.translateIn() self.privTranslateIn()
} }
} }
if let vc = viewController ?? cfg.rootViewController { if let vc = viewController ?? cfg.rootViewController {
@ -127,7 +126,7 @@ public extension Guard {
view.isUserInteractionEnabled = false view.isUserInteractionEnabled = false
self.removeFromParent() self.removeFromParent()
UIView.animateForGuard(animations: { UIView.animateForGuard(animations: {
self.translateOut() self.privTranslateOut()
}) { (done) in }) { (done) in
if self.displaying == false { if self.displaying == false {
self.view.removeFromSuperview() self.view.removeFromSuperview()
@ -136,92 +135,23 @@ public extension Guard {
} }
} }
// MARK: ///
/// - Parameter callback:
/// func update(_ callback: ((inout ViewModel) -> Void)? = nil) {
/// - Parameter text: callback?(&vm)
@discardableResult func add(title: String?) -> UILabel { cfg.guard.reloadData(self)
let lb = UILabel()
lb.font = cfg.guard.titleFont
lb.textColor = cfg.primaryLabelColor
lb.numberOfLines = 0
lb.textAlignment = .justified
lb.text = title
textStack.addArrangedSubview(lb)
if #available(iOS 11.0, *) {
let count = textStack.arrangedSubviews.count
if count > 1 {
textStack.setCustomSpacing(cfg.guard.margin * 2, after: textStack.arrangedSubviews[count-2])
}
} else {
// Fallback on earlier versions
}
cfg.guard.reloadStack(self)
return lb
} }
///
/// - Parameter text:
@discardableResult func add(subTitle: String?) -> UILabel {
let lb = add(title: subTitle)
lb.font = cfg.guard.subTitleFont
return lb
}
///
/// - Parameter text:
@discardableResult func add(message: String?) -> UILabel {
let lb = UILabel()
lb.font = cfg.guard.bodyFont
lb.textColor = cfg.secondaryLabelColor
lb.numberOfLines = 0
lb.textAlignment = .justified
lb.text = message
textStack.addArrangedSubview(lb)
cfg.guard.reloadStack(self)
return lb
}
///
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
let btn = Button.actionButton(title: title)
btn.titleLabel?.font = cfg.guard.buttonFont
actionStack.addArrangedSubview(btn)
cfg.guard.reloadStack(self)
btn.update(style: style)
addTouchUpAction(for: btn) { [weak self] in
handler?()
if btn.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop()
}
}
return btn
}
///
/// - Parameter index:
@discardableResult func remove(action index: Int...) -> Guard {
for (i, idx) in index.enumerated() {
privRemoveAction(index: idx-i)
}
return self
}
/// ///
/// - Parameter callback: /// - Parameter callback:
@discardableResult func didDisappear(_ callback: (() -> Void)?) -> Guard { func didDisappear(_ callback: (() -> Void)?) {
disappearCallback = callback disappearCallback = callback
return self
} }
} }
// MARK: -
// MARK:
public extension Guard { public extension Guard {
/// ///
@ -261,7 +191,7 @@ public extension Guard {
`guard`.pop() `guard`.pop()
} }
/// ///
/// - Parameter identifier: /// - Parameter identifier:
class func pop(from viewController: UIViewController?) { class func pop(from viewController: UIViewController?) {
for g in guards(from: viewController) { for g in guards(from: viewController) {
@ -273,36 +203,103 @@ public extension Guard {
// MARK: - // MARK: -
internal extension Guard { internal extension Guard {
/// ///
/// - Parameter sender: /// - Parameter text:
@objc func privDidTapped(_ sender: UITapGestureRecognizer) { @discardableResult func add(title: String?) -> UILabel {
let point = sender.location(in: contentView) let lb = UILabel()
if point.x < 0 || point.y < 0 { lb.font = cfg.guard.titleFont
if force == false { lb.textColor = cfg.primaryLabelColor
// lb.numberOfLines = 0
pop() lb.textAlignment = .center
lb.text = title
textStack.addArrangedSubview(lb)
if #available(iOS 11.0, *) {
let count = textStack.arrangedSubviews.count
if count > 1 {
textStack.setCustomSpacing(cfg.guard.margin * 2, after: textStack.arrangedSubviews[count-2])
}
} else {
// Fallback on earlier versions
}
cfg.guard.reloadStack(self)
return lb
}
///
/// - Parameter text:
@discardableResult func add(subTitle: String?) -> UILabel {
let lb = add(title: subTitle)
lb.font = cfg.guard.subTitleFont
lb.textAlignment = .justified
return lb
}
///
/// - Parameter text:
@discardableResult func add(message: String?) -> UILabel {
let lb = UILabel()
lb.font = cfg.guard.bodyFont
lb.textColor = cfg.secondaryLabelColor
lb.numberOfLines = 0
lb.textAlignment = .justified
lb.text = message
textStack.addArrangedSubview(lb)
cfg.guard.reloadStack(self)
return lb
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func insert(action index: Int?, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
let btn = Button.actionButton(title: title)
btn.titleLabel?.font = cfg.guard.buttonFont
if let idx = index, idx < actionStack.arrangedSubviews.count {
actionStack.insertArrangedSubview(btn, at: idx)
} else {
actionStack.addArrangedSubview(btn)
}
btn.update(style: style)
cfg.guard.reloadStack(self)
addTouchUpAction(for: btn) { [weak self] in
handler?()
if btn.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop()
} }
} }
if isLoadFinished {
UIView.animateForGuard {
self.view.layoutIfNeeded()
}
}
return btn
} }
func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
func translateIn() { if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
view.backgroundColor = backgroundColor btn.setTitle(title, for: .normal)
contentView.transform = .identity if let b = btn as? Button {
} b.update(style: style)
}
func translateOut() { if let _ = buttonEvents[btn] {
view.backgroundColor = UIColor(white: 0, alpha: 0) buttonEvents.removeValue(forKey: btn)
contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + cfg.guard.margin) }
addTouchUpAction(for: btn) { [weak self] in
handler?()
if btn.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop()
}
}
}
} }
/// ///
/// - Parameter index: /// - Parameter index:
@discardableResult func privRemoveAction(index: Int) -> Guard { @discardableResult func remove(index: Int) -> Guard {
if index < 0 { if index < 0 {
for view in self.actionStack.arrangedSubviews { for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton { if let btn = view as? UIButton {
@ -322,3 +319,29 @@ internal extension Guard {
} }
fileprivate extension Guard {
///
/// - Parameter sender:
@objc func privDidTapped(_ sender: UITapGestureRecognizer) {
let point = sender.location(in: contentView)
if point.x < 0 || point.y < 0 {
if force == false {
//
pop()
}
}
}
func privTranslateIn() {
view.backgroundColor = backgroundColor
contentView.transform = .identity
}
func privTranslateOut() {
view.backgroundColor = UIColor(white: 0, alpha: 0)
contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + cfg.guard.margin)
}
}

View File

@ -10,7 +10,7 @@ import UIKit
public extension Guard { public extension Guard {
struct ViewModel { class ViewModel {
/// ID /// ID
public var identifier = String(Date().timeIntervalSince1970) public var identifier = String(Date().timeIntervalSince1970)
@ -46,7 +46,7 @@ public extension Guard.ViewModel {
/// - Parameter title: /// - Parameter title:
/// - Parameter action: /// - Parameter action:
@discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { @discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
return vc!.add(action: style, title: title, handler: handler) return vc!.insert(action: nil, style: style, title: title, handler: handler)
} }
/// ///
@ -54,9 +54,8 @@ public extension Guard.ViewModel {
/// - Parameter style: /// - Parameter style:
/// - Parameter title: /// - Parameter title:
/// - Parameter handler: /// - Parameter handler:
@discardableResult mutating func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { @discardableResult func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
return vc!.insert(action: index, style: style, title: title, handler: handler)
return UIButton()
} }
/// ///
@ -64,15 +63,15 @@ public extension Guard.ViewModel {
/// - Parameter style: /// - Parameter style:
/// - Parameter title: /// - Parameter title:
/// - Parameter handler: /// - Parameter handler:
mutating func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
// vc?.privUpdateButton(action: index, style: style, title: title, handler) vc?.update(action: index, style: style, title: title, handler: handler)
} }
/// ///
/// - Parameter index: /// - Parameter index:
func remove(action index: Int...) { func remove(action index: Int...) {
for (i, idx) in index.enumerated() { for (i, idx) in index.enumerated() {
vc!.privRemoveAction(index: idx-i) vc?.remove(index: idx-i)
} }
} }

View File

@ -1,46 +0,0 @@
//
// GuardView.swift
// ProHUD
//
// Created by xaoxuu on 2019/7/31.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
internal extension Guard {
class Button: UIButton {
class func actionButton(title: String?) -> Button {
let btn = Button(type: .system)
btn.setTitle(title, for: .normal)
btn.layer.cornerRadius = cfg.guard.buttonCornerRadius
btn.titleLabel?.font = cfg.guard.buttonFont
return btn
}
func update(style: UIAlertAction.Style) {
let pd = CGFloat(8)
if style != .cancel {
contentEdgeInsets = .init(top: pd*1.5+2, left: pd*1.5, bottom: pd*1.5+2, right: pd*1.5)
} else {
contentEdgeInsets = .init(top: pd*1+2, left: pd*1.5, bottom: pd*1+2, right: pd*1.5)
}
switch style {
case .default:
backgroundColor = tintColor
setTitleColor(.white, for: .normal)
case .destructive:
backgroundColor = .init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1)
setTitleColor(.white, for: .normal)
case .cancel:
setTitleColor(cfg.secondaryLabelColor, for: .normal)
@unknown default:
break
}
tag = style.rawValue
}
}
}

View File

@ -19,19 +19,19 @@ public extension ProHUD {
/// iOS13 /// iOS13
public lazy var dynamicColor: UIColor = { public lazy var dynamicColor: UIColor = {
// if #available(iOS 13.0, *) { 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 .white return .init(white: 1, alpha: 1)
// } else { } else {
// return .black return .init(white: 0.1, alpha: 1)
// } }
// } }
// return color return color
// } else { } else {
// // Fallback on earlier versions // Fallback on earlier versions
// } }
return .init(white: 0.15, alpha: 1) return .init(white: 0.1, alpha: 1)
}() }()
/// ///
@ -41,9 +41,13 @@ public extension ProHUD {
/// ///
public lazy var secondaryLabelColor: UIColor = { public lazy var secondaryLabelColor: UIColor = {
return dynamicColor.withAlphaComponent(0.6) return dynamicColor.withAlphaComponent(0.66)
}() }()
public func blurView(_ callback: @escaping () -> UIVisualEffectView) {
createBlurView = callback
}
public var toast = Toast() public var toast = Toast()
public var alert = Alert() public var alert = Alert()
@ -78,3 +82,19 @@ public extension ProHUD {
config(&cfg) config(&cfg)
} }
} }
internal var createBlurView: () -> UIVisualEffectView = {
return {
let vev = UIVisualEffectView()
if #available(iOS 13.0, *) {
vev.effect = UIBlurEffect(style: .systemMaterial)
// vev.effect = UIBlurEffect(style: .extraLight)
} else if #available(iOS 11.0, *) {
vev.effect = UIBlurEffect(style: .extraLight)
} else {
vev.effect = .none
vev.backgroundColor = .white
}
return vev
}
}()

View File

@ -27,34 +27,94 @@ public extension ProHUD {
} }
class BlurView: UIVisualEffectView { }
init() {
if #available(iOS 13.0, *) {
// super.init(effect: UIBlurEffect(style: .systemMaterial))
super.init(effect: UIBlurEffect(style: .extraLight))
} else if #available(iOS 11.0, *) {
super.init(effect: UIBlurEffect(style: .extraLight))
} else {
super.init(effect: .none)
backgroundColor = .white
}
internal extension Alert {
class Button: UIButton {
class func actionButton(title: String?) -> Button {
let btn = Button(type: .system)
btn.setTitle(title, for: .normal)
btn.layer.cornerRadius = cfg.alert.cornerRadius / 2
btn.titleLabel?.font = cfg.alert.buttonFont
return btn
} }
required init?(coder: NSCoder) { func update(style: UIAlertAction.Style) {
fatalError("init(coder:) has not been implemented") let pd = CGFloat(8)
if style != .cancel {
backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04)
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
} else {
backgroundColor = .clear
contentEdgeInsets = .init(top: pd*0.5, left: pd*1.5, bottom: pd*0.5, right: pd*1.5)
}
switch style {
case .default:
setTitleColor(tintColor, for: .normal)
case .destructive:
setTitleColor(.init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1), for: .normal)
case .cancel:
setTitleColor(cfg.secondaryLabelColor, for: .normal)
@unknown default:
break
}
tag = style.rawValue
}
class func forceQuitButton() -> UIButton {
let btn = Button(type: .system)
let pd = cfg.alert.padding/2
btn.contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
btn.imageEdgeInsets.right = pd*1.5
btn.setTitleColor(UIColor(red:1.00, green:0.55, blue:0.21, alpha:1.00), for: .normal)
btn.titleLabel?.font = cfg.alert.buttonFont
return btn
} }
} }
}
internal extension Guard {
class Button: UIButton {
class func actionButton(title: String?) -> Button {
let btn = Button(type: .system)
btn.setTitle(title, for: .normal)
btn.layer.cornerRadius = cfg.guard.buttonCornerRadius
btn.titleLabel?.font = cfg.guard.buttonFont
return btn
}
func update(style: UIAlertAction.Style) {
let pd = CGFloat(8)
if style != .cancel {
contentEdgeInsets = .init(top: pd*1.5+2, left: pd*1.5, bottom: pd*1.5+2, right: pd*1.5)
} else {
contentEdgeInsets = .init(top: pd*1+2, left: pd*1.5, bottom: pd*1+2, right: pd*1.5)
}
switch style {
case .default:
backgroundColor = tintColor
setTitleColor(.white, for: .normal)
case .destructive:
backgroundColor = .init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1)
setTitleColor(.white, for: .normal)
case .cancel:
backgroundColor = .clear
setTitleColor(cfg.secondaryLabelColor, for: .normal)
@unknown default:
break
}
tag = style.rawValue
}
}
} }
internal extension UIView { internal extension UIView {
class func animateEaseOut(duration: TimeInterval = 1, delay: TimeInterval = 0, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { private class func animateEaseOut(duration: TimeInterval = 1, delay: TimeInterval = 0, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
animate(withDuration: duration, delay: delay, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion) animate(withDuration: duration, delay: delay, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion)
} }
@ -64,27 +124,26 @@ internal extension UIView {
class func animateForAlertBuildOut(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { class func animateForAlertBuildOut(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
animateEaseOut(duration: 0.38, delay: 0, animations: animations, completion: completion) animateEaseOut(duration: 0.38, delay: 0, animations: animations, completion: completion)
} }
class func animateForAlert(animations: @escaping () -> Void) {
animateEaseOut(duration: 1, delay: 0, animations: animations, completion: nil)
}
class func animateForAlert(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { class func animateForAlert(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
animateEaseOut(duration: 1, delay: 0, animations: animations, completion: completion) animateEaseOut(duration: 1, delay: 0, animations: animations, completion: completion)
} }
class func animateForAlert(animations: @escaping () -> Void) {
class func animateForToast(animations: @escaping () -> Void) { animateForAlert(animations: animations, completion: nil)
animateEaseOut(duration: 1, delay: 0, animations: animations, completion: nil)
} }
class func animateForToast(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { class func animateForToast(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
animateEaseOut(duration: 1, delay: 0, animations: animations, completion: completion) animateEaseOut(duration: 1.2, delay: 0, animations: animations, completion: completion)
} }
class func animateForToast(animations: @escaping () -> Void) {
class func animateForGuard(animations: @escaping () -> Void) { animateForToast(animations: animations, completion: nil)
animateForGuard(animations: animations, completion: nil)
} }
class func animateForGuard(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { class func animateForGuard(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
animateEaseOut(duration: 0.6, delay: 0, animations: animations, completion: completion) animateEaseOut(duration: 0.6, delay: 0, animations: animations, completion: completion)
} }
class func animateForGuard(animations: @escaping () -> Void) {
animateForGuard(animations: animations, completion: nil)
}
} }

View File

@ -21,10 +21,13 @@ public extension ProHUD.Configuration {
public var padding = CGFloat(16) public var padding = CGFloat(16)
// MARK: // MARK:
/// default
public var tintColor: UIColor?
/// ///
public var iconSize = CGSize(width: 48, height: 48) public var iconSize = CGSize(width: 48, height: 48)
///
/// - Parameter callback:
public func iconForScene(_ callback: @escaping (ProHUD.Toast.Scene) -> UIImage?) {
privIconForScene = callback
}
// MARK: // MARK:
/// ///
@ -37,71 +40,49 @@ public extension ProHUD.Configuration {
/// ///
public var bodyMaxLines = Int(10) public var bodyMaxLines = Int(10)
/// View
/// - Parameter callback:
public mutating func loadSubviews(_ callback: @escaping (ProHUD.Toast) -> Void) {
privLoadSubviews = callback
}
/// ///
/// - Parameter callback: /// - Parameter callback:
public mutating func reloadData(_ callback: @escaping (ProHUD.Toast) -> Void) { public mutating func reloadData(_ callback: @escaping (ProHUD.Toast) -> Void) {
privReloadData = callback privReloadData = callback
} }
/// Loading
public var duration = TimeInterval(3)
} }
} }
// MARK: -
// MARK: -
internal extension ProHUD.Configuration.Toast { internal extension ProHUD.Configuration.Toast {
var loadSubviews: (ProHUD.Toast) -> Void {
return privLoadSubviews
}
var reloadData: (ProHUD.Toast) -> Void { var reloadData: (ProHUD.Toast) -> Void {
return privReloadData return privReloadData
} }
} }
fileprivate var privLoadSubviews: (ProHUD.Toast) -> Void = { // MARK: -
return { (vc) in
debug(vc, "loadSubviews")
vc.view.tintColor = cfg.toast.tintColor
vc.view.addSubview(vc.titleLabel)
vc.view.addSubview(vc.bodyLabel)
vc.view.addSubview(vc.imageView)
}
}()
fileprivate var privReloadData: (ProHUD.Toast) -> Void = { 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.model.scene let scene = vc.vm.scene
// if vc.titleLabel.superview == nil {
let imgStr: String vc.view.addSubview(vc.titleLabel)
switch vc.model.scene {
case .success:
imgStr = "ProHUDSuccess"
case .warning:
imgStr = "ProHUDWarning"
case .error:
imgStr = "ProHUDError"
case .loading:
imgStr = "ProHUDLoading"
case .confirm:
imgStr = "ProHUDMessage"
case .delete:
imgStr = "ProHUDTrash"
default:
imgStr = "ProHUDMessage"
} }
let img = vc.model.icon ?? ProHUD.image(named: imgStr) if vc.bodyLabel.superview == nil {
vc.imageView.image = img vc.view.addSubview(vc.bodyLabel)
}
if vc.imageView.superview == nil {
vc.view.addSubview(vc.imageView)
}
//
vc.imageView.image = vc.vm.icon ?? privIconForScene(vc.vm.scene)
vc.titleLabel.textColor = cfg.primaryLabelColor vc.titleLabel.textColor = cfg.primaryLabelColor
vc.titleLabel.text = vc.model.title vc.titleLabel.text = vc.vm.title
vc.bodyLabel.textColor = cfg.secondaryLabelColor vc.bodyLabel.textColor = cfg.secondaryLabelColor
vc.bodyLabel.text = vc.model.message vc.bodyLabel.text = vc.vm.message
// //
vc.imageView.snp.makeConstraints { (mk) in vc.imageView.snp.makeConstraints { (mk) in
@ -123,13 +104,35 @@ fileprivate var privReloadData: (ProHUD.Toast) -> Void = {
} }
vc.view.layoutIfNeeded() vc.view.layoutIfNeeded()
switch vc.model.scene { //
case .loading: if vc.vm.duration == nil {
vc.duration(nil) if vc.vm.scene == .loading {
default: vc.vm.duration = 0
vc.duration(3) } else {
vc.vm.duration = config.duration
}
} }
} }
}() }()
fileprivate var privIconForScene: (ProHUD.Toast.Scene) -> UIImage? = {
return { (scene) in
let imgStr: String
switch scene {
case .success:
imgStr = "ProHUDSuccess"
case .warning:
imgStr = "ProHUDWarning"
case .error:
imgStr = "ProHUDError"
case .loading:
imgStr = "ProHUDLoading"
default:
imgStr = "ProHUDMessage"
}
return ProHUD.image(named: imgStr)
}
}()

View File

@ -47,23 +47,16 @@ public extension ProHUD {
/// ///
public var backgroundView: UIVisualEffectView = { public var backgroundView: UIVisualEffectView = {
let vev = UIVisualEffectView() let vev = createBlurView()
if #available(iOS 13.0, *) {
// vev.effect = UIBlurEffect.init(style: .systemMaterial))
vev.effect = UIBlurEffect.init(style: .extraLight)
} else if #available(iOS 11.0, *) {
vev.effect = UIBlurEffect.init(style: .extraLight)
} else {
vev.effect = .none
vev.backgroundColor = .white
}
vev.layer.masksToBounds = true vev.layer.masksToBounds = true
vev.layer.cornerRadius = cfg.toast.cornerRadius vev.layer.cornerRadius = cfg.toast.cornerRadius
return vev return vev
}() }()
/// ///
public var model = ViewModel() public var vm = ViewModel()
internal var maxY = CGFloat(0)
// MARK: // MARK:
@ -72,17 +65,15 @@ public extension ProHUD {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter icon: /// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, actions: ((Toast) -> Void)? = nil) { public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, actions: ((inout ViewModel) -> Void)? = nil) {
self.init() self.init()
vm.vc = self
model.scene = scene vm.scene = scene
model.title = title vm.title = title
model.message = message vm.message = message
model.icon = icon vm.icon = icon
actions?(self) actions?(&vm)
//
cfg.toast.loadSubviews(self)
cfg.toast.reloadData(self)
// //
let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:))) let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:)))
@ -94,16 +85,21 @@ public extension ProHUD {
} }
public override func viewDidLoad() {
super.viewDidLoad()
cfg.toast.reloadData(self)
}
} }
} }
// MARK: - // MARK: -
public extension Toast { public extension Toast {
// MARK:
/// ///
@discardableResult func push() -> Toast { @discardableResult func push() -> Toast {
let config = cfg.toast let config = cfg.toast
@ -145,7 +141,7 @@ public extension Toast {
if Toast.toasts.contains(self) == false { if Toast.toasts.contains(self) == false {
Toast.toasts.append(self) Toast.toasts.append(self)
} }
Toast.updateToastsLayout() Toast.privUpdateToastsLayout()
if isNew { if isNew {
window.transform = .init(translationX: 0, y: -window.frame.maxY) window.transform = .init(translationX: 0, y: -window.frame.maxY)
UIView.animateForToast { UIView.animateForToast {
@ -159,32 +155,21 @@ public extension Toast {
/// ///
func pop() { func pop() {
Toast.removeItemFromArray(toast: self) Toast.pop(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
}
} }
// MARK:
/// ///
/// - Parameter duration: /// - Parameter callback:
@discardableResult func duration(_ duration: TimeInterval?) -> Toast { func update(_ callback: ((inout ViewModel) -> Void)? = nil) {
model.setupDuration(duration: duration) { [weak self] in callback?(&vm)
self?.pop() cfg.toast.reloadData(self)
}
return self
} }
/// ///
/// - Parameter callback: /// - Parameter callback:
@discardableResult func didTapped(_ callback: (() -> Void)?) -> Toast { @discardableResult func didTapped(_ callback: (() -> Void)?) -> Toast {
model.tapCallback = callback vm.tapCallback = callback
return self return self
} }
@ -195,47 +180,10 @@ public extension Toast {
return self return self
} }
///
/// - Parameter scene:
/// - Parameter title:
/// - Parameter message:
@discardableResult func update(scene: Scene, title: String?, message: String?) -> Toast {
model.scene = scene
model.title = title
model.message = message
cfg.toast.reloadData(self)
return self
}
///
/// - Parameter title:
@discardableResult func update(title: String?) -> Toast {
model.title = title
cfg.toast.reloadData(self)
return self
}
///
/// - Parameter message:
@discardableResult func update(message: String?) -> Toast {
model.message = message
cfg.toast.reloadData(self)
return self
}
///
/// - Parameter icon:
@discardableResult func update(icon: UIImage?) -> Toast {
model.icon = icon
cfg.toast.reloadData(self)
return self
}
} }
// MARK: // MARK: -
public extension Toast { public extension Toast {
/// ///
@ -243,7 +191,7 @@ public extension Toast {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter actions: /// - Parameter actions:
@discardableResult class func push(scene: Toast.Scene, title: String? = nil, message: String? = nil, actions: ((Toast) -> Void)? = nil) -> Toast { @discardableResult class func push(scene: Toast.Scene = .default, title: String? = nil, message: String? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Toast {
return Toast(scene: scene, title: title, message: message, actions: actions).push() return Toast(scene: scene, title: title, message: message, actions: actions).push()
} }
@ -252,7 +200,7 @@ public extension Toast {
class func toasts(_ identifier: String?) -> [Toast] { class func toasts(_ identifier: String?) -> [Toast] {
var tt = [Toast]() var tt = [Toast]()
for t in toasts { for t in toasts {
if t.model.identifier == identifier { if t.vm.identifier == identifier {
tt.append(t) tt.append(t)
} }
} }
@ -262,7 +210,25 @@ public extension Toast {
/// ///
/// - Parameter toast: /// - Parameter toast:
class func pop(_ toast: Toast) { class func pop(_ toast: Toast) {
toast.pop() if toasts.count > 1 {
for (i, t) in toasts.enumerated() {
if t == toast {
toasts.remove(at: i)
}
}
privUpdateToastsLayout()
} else if toasts.count == 1 {
toasts.removeAll()
} else {
debug("漏洞已经没有toast了")
}
UIView.animateForToast(animations: {
toast.window?.transform = .init(translationX: 0, y: -20-toast.maxY)
}) { (done) in
toast.view.removeFromSuperview()
toast.removeFromParent()
toast.window = nil
}
} }
/// ///
@ -275,57 +241,40 @@ public extension Toast {
} }
// MARK: // MARK: -
fileprivate var willprivUpdateToastsLayout: DispatchWorkItem?
fileprivate var willUpdateToastsLayout: DispatchWorkItem?
fileprivate extension Toast { fileprivate extension Toast {
/// ///
/// - Parameter sender: /// - Parameter sender:
@objc func privDidTapped(_ sender: UITapGestureRecognizer) { @objc func privDidTapped(_ sender: UITapGestureRecognizer) {
model.tapCallback?() vm.tapCallback?()
} }
/// ///
/// - Parameter sender: /// - Parameter sender:
@objc func privDidPan(_ sender: UIPanGestureRecognizer) { @objc func privDidPan(_ sender: UIPanGestureRecognizer) {
model.durationBlock?.cancel() vm.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 model.removable == true && (((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200) { if vm.removable == true && (((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200) {
// //
self.pop() self.pop()
} else { } else {
UIView.animateForToast(animations: { UIView.animateForToast(animations: {
self.window?.transform = .identity self.window?.transform = .identity
}) { (done) in }) { (done) in
// FIXME: let d = self.vm.duration
self.vm.duration = d
} }
} }
} }
} }
/// class func privUpdateToastsLayout() {
/// - Parameter toast:
class func removeItemFromArray(toast: Toast) {
if toasts.count > 1 {
for (i, t) in toasts.enumerated() {
if t == toast {
toasts.remove(at: i)
}
}
updateToastsLayout()
} else if toasts.count == 1 {
toasts.removeAll()
} else {
debug("漏洞已经没有toast了")
}
}
class func updateToastsLayout() {
func f() { func f() {
let top = Inspire.shared.screen.updatedSafeAreaInsets.top let top = Inspire.shared.screen.updatedSafeAreaInsets.top
for (i, e) in toasts.enumerated() { for (i, e) in toasts.enumerated() {
@ -342,18 +291,20 @@ fileprivate extension Toast {
let lastY = toasts[i-1].window?.frame.maxY ?? .zero let lastY = toasts[i-1].window?.frame.maxY ?? .zero
y = lastY + config.margin y = lastY + config.margin
} }
e.maxY = y + window.frame.size.height
UIView.animateForToast { UIView.animateForToast {
e.window?.frame.origin.y = y window.frame.origin.y = y
} }
} }
} }
} }
willUpdateToastsLayout?.cancel() willprivUpdateToastsLayout?.cancel()
willUpdateToastsLayout = DispatchWorkItem(block: { willprivUpdateToastsLayout = DispatchWorkItem(block: {
f() f()
}) })
DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willUpdateToastsLayout!) DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willprivUpdateToastsLayout!)
} }
} }

View File

@ -16,12 +16,6 @@ public extension Toast {
/// ///
case loading case loading
///
case confirm
///
case delete
/// ///
case success case success
@ -33,7 +27,7 @@ public extension Toast {
} }
struct ViewModel { class ViewModel {
/// ID /// ID
public var identifier = String(Date().timeIntervalSince1970) public var identifier = String(Date().timeIntervalSince1970)
@ -42,40 +36,56 @@ public extension Toast {
public var scene = Scene.default public var scene = Scene.default
/// ///
public var title: String? public var title: String? {
didSet {
vc?.titleLabel.text = title
}
}
/// ///
public var message: String? public var message: String? {
didSet {
vc?.bodyLabel.text = message
}
}
/// ///
public var icon: UIImage? public var icon: UIImage? {
didSet {
vc?.imageView.image = icon
}
}
/// ///
internal var duration: TimeInterval? public var duration: TimeInterval? {
didSet {
durationBlock?.cancel()
if let t = duration, t > 0 {
durationBlock = DispatchWorkItem(block: { [weak self] in
self?.vc?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
}
public weak var vc: Toast?
///
public var removable = true
// MARK:
/// ///
internal var durationBlock: DispatchWorkItem? internal var durationBlock: DispatchWorkItem?
///
public var removable = true
/// ///
internal var tapCallback: (() -> Void)? internal var tapCallback: (() -> Void)?
internal mutating func setupDuration(duration: TimeInterval?, callback: @escaping () -> Void) {
self.duration = duration
durationBlock?.cancel()
if let t = duration, t > 0 {
durationBlock = DispatchWorkItem(block: callback)
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
} }
} }

View File

@ -1,9 +0,0 @@
//
// ToastView.swift
// ProHUD
//
// Created by xaoxuu on 2019/7/31.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import Foundation