mirror of https://github.com/xaoxuu/ProHUD
update
This commit is contained in:
parent
26d7aa0049
commit
ca6c36650b
|
@ -22,8 +22,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 */,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
/// 内容容器(包括icon、textStack、actionStack)
|
/// 内容容器(包括icon、textStack、actionStack)
|
||||||
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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 {
|
||||||
|
let bottom = Inspire.shared.screen.safeAreaInsets.bottom
|
||||||
|
if bottom == 0 {
|
||||||
mk.bottom.equalToSuperview().offset(-config.padding)
|
mk.bottom.equalToSuperview().offset(-config.padding)
|
||||||
} else {
|
} else {
|
||||||
mk.bottom.equalToSuperview().offset(-config.padding-Inspire.shared.screen.safeAreaInsets.bottom)
|
mk.bottom.equalToSuperview().offset(-config.padding/2 - bottom)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -15,7 +15,7 @@ public extension ProHUD {
|
||||||
class Guard: HUDController {
|
class Guard: HUDController {
|
||||||
|
|
||||||
/// 内容视图
|
/// 内容视图
|
||||||
public var contentView = BlurView()
|
public var contentView = createBlurView()
|
||||||
|
|
||||||
/// 内容容器(包括textStack、actionStack,可以自己插入需要的控件)
|
/// 内容容器(包括textStack、actionStack,可以自己插入需要的控件)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateIn() {
|
/// 加载一段正文
|
||||||
view.backgroundColor = backgroundColor
|
/// - Parameter text: 文本
|
||||||
contentView.transform = .identity
|
@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
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateOut() {
|
/// 加载一个按钮
|
||||||
view.backgroundColor = UIColor(white: 0, alpha: 0)
|
/// - Parameter index: 索引
|
||||||
contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + cfg.guard.margin)
|
/// - 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)?) {
|
||||||
|
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
|
||||||
|
btn.setTitle(title, for: .normal)
|
||||||
|
if let b = btn as? Button {
|
||||||
|
b.update(style: style)
|
||||||
|
}
|
||||||
|
if let _ = buttonEvents[btn] {
|
||||||
|
buttonEvents.removeValue(forKey: btn)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
|
@ -27,34 +27,94 @@ public extension ProHUD {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlurView: UIVisualEffectView {
|
}
|
||||||
|
|
||||||
init() {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
if #available(iOS 13.0, *) {
|
func update(style: UIAlertAction.Style) {
|
||||||
// super.init(effect: UIBlurEffect(style: .systemMaterial))
|
let pd = CGFloat(8)
|
||||||
super.init(effect: UIBlurEffect(style: .extraLight))
|
if style != .cancel {
|
||||||
} else if #available(iOS 11.0, *) {
|
backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04)
|
||||||
super.init(effect: UIBlurEffect(style: .extraLight))
|
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
|
||||||
} else {
|
} else {
|
||||||
super.init(effect: .none)
|
backgroundColor = .clear
|
||||||
backgroundColor = .white
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
}
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
|
@ -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!)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
/// 持续时间
|
|
||||||
internal var durationBlock: DispatchWorkItem?
|
|
||||||
|
|
||||||
/// 是否可以通过手势移除(向上划)
|
|
||||||
public var removable = true
|
|
||||||
|
|
||||||
/// 点击事件回调
|
|
||||||
internal var tapCallback: (() -> Void)?
|
|
||||||
|
|
||||||
internal mutating func setupDuration(duration: TimeInterval?, callback: @escaping () -> Void) {
|
|
||||||
self.duration = duration
|
|
||||||
durationBlock?.cancel()
|
durationBlock?.cancel()
|
||||||
if let t = duration, t > 0 {
|
if let t = duration, t > 0 {
|
||||||
durationBlock = DispatchWorkItem(block: callback)
|
durationBlock = DispatchWorkItem(block: { [weak self] in
|
||||||
|
self?.vc?.pop()
|
||||||
|
})
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
|
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
|
||||||
} else {
|
} else {
|
||||||
durationBlock = nil
|
durationBlock = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public weak var vc: Toast?
|
||||||
|
|
||||||
|
/// 是否可以通过手势移除(向上滑出屏幕)
|
||||||
|
public var removable = true
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: 私有
|
||||||
|
|
||||||
|
/// 持续时间
|
||||||
|
internal var durationBlock: DispatchWorkItem?
|
||||||
|
|
||||||
|
/// 点击事件回调
|
||||||
|
internal var tapCallback: (() -> Void)?
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
//
|
|
||||||
// ToastView.swift
|
|
||||||
// ProHUD
|
|
||||||
//
|
|
||||||
// Created by xaoxuu on 2019/7/31.
|
|
||||||
// Copyright © 2019 Titan Studio. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
Loading…
Reference in New Issue