This commit is contained in:
xaoxuu 2020-06-23 20:16:12 +08:00
parent 539ad04623
commit ad3576cf6f
8 changed files with 589 additions and 487 deletions

View File

@ -30,7 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// a.bodyFont = .regular(17)
// a.boldTextFont = .bold(18)
// a.buttonFont = .bold(18)
a.forceQuitTimer = 3
a.forceQuitTimer = 5 // 便
}
// cfg.toast { (t) in
// t.titleFont = .bold(18)
@ -78,7 +78,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
extension ProHUD.Scene {
static var delete: ProHUD.Scene {
var scene = ProHUD.Scene(identifier: "delete")
var scene = ProHUD.Scene(identifier: "prohud.delete")
scene.image = UIImage(named: "prohud.trash")
scene.title = "确认删除"
scene.message = "此操作不可撤销"

View File

@ -8,18 +8,46 @@
import UIKit
typealias Callback = () -> Void
struct Table {
var sections = [Section]()
mutating func addSection(title: String, callback: @escaping (inout Section) -> Void) {
var sec = Section()
sec.header = title
callback(&sec)
sections.append(sec)
}
}
struct Section {
var header = ""
var footer = ""
var rows = [Row]()
mutating func addRow(title: String, subtitle: String? = nil, callback: @escaping Callback) {
rows.append(Row(title: title, subtitle: subtitle, callback: callback))
}
}
struct Row {
var title: String
var subtitle: String?
var callback: Callback
}
class BaseListVC: UIViewController {
var ts = [[String]]()
var cs = [[Callback]]()
var vm = Table()
var secs = [Section]()
lazy var tableView: UITableView = {
let tv = UITableView()
let tv = UITableView(frame: .zero, style: .grouped)
return tv
}()
var titles: [String] {
return ["Toast", "Alert", "Guard"]
}
override func viewDidLoad() {
super.viewDidLoad()
@ -27,29 +55,47 @@ class BaseListVC: UIViewController {
view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.snp.makeConstraints { (mk) in
mk.edges.equalToSuperview()
}
}
}
extension BaseListVC: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return vm.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
return vm.sections[section].rows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = titles[indexPath.row]
let cell: UITableViewCell
if let c = tableView.dequeueReusableCell(withIdentifier: "cell") {
cell = c
} else {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
cell.textLabel?.numberOfLines = 0
cell.detailTextLabel?.textColor = .gray
cell.detailTextLabel?.numberOfLines = 0
}
cell.textLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].title
cell.detailTextLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].subtitle
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return vm.sections[section].header
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return vm.sections[section].footer
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
vm.sections[indexPath.section].rows[indexPath.row].callback()
}
}

View File

@ -9,219 +9,252 @@
import UIKit
import ProHUD
// 2
func loadingSuccessAfter2Seconds() {
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
Alert.find("loading", last: { (a) in
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
}
})
}
}
class TestAlertVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
vm.addSection(title: "最简单的写法") { (sec) in
sec.addRow(title: "Alert.push(scene: .loading)") {
Alert.push(scene: .loading)
}
sec.addRow(title: "Alert.push(scene: .success)") {
Alert.push(scene: .success)
}
sec.addRow(title: "Alert.push(scene: .warning)") {
Alert.push(scene: .warning)
}
sec.addRow(title: "Alert.push(scene: .error)") {
Alert.push(scene: .error)
}
sec.addRow(title: "Alert.push(scene: .failure)") {
Alert.push(scene: .failure)
}
sec.footer = "这些是自带的场景,可以重写已有场景,或者扩展新的场景。"
}
override var titles: [String] {
return ["极端场景:正在同步(超时未处理)",
"场景同步成功写法1",
"场景同步成功写法2",
"场景:同步失败和重试",
"极端场景:短时间内调用了多次同一个弹窗",
"极端场景:多个不同的弹窗重叠",
"测试较长的标题和内容",
"测试特别长的标题和内容",
"场景:正在同步(更新进度)"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
func f() {
Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (a) in
a.identifier = "loading"
a.startRotate()
a.didForceQuit {
let t = Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻点击展开为Alert") { (vm) in
vm.identifier = "loading"
}
t.startRotate()
t.didTapped { [weak t] in
t?.pop()
f()
}
}
}
}
f()
} else if row == 1 {
Alert.push() { (a) in
a.identifier = "loading"
a.startRotate()
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
}
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
Alert.find("loading", last: { (a) in
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
}
})
}
} else if row == 2 {
let a = Alert.push() { (a) in
a.identifier = "loading"
}
a.startRotate()
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
Alert.find("loading", last: { (a) in
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
}
})
}
} else if row == 3 {
Alert.push() { (a) in
a.identifier = "loading"
}
func loading() {
Alert.find("loading", last: { (a) in
vm.addSection(title: "常用场景示例") { (sec) in
// MARK: 1
sec.addRow(title: "场景同步成功写法1") {
Alert.push("loading") { (a) in
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
vm.remove(action: 0, 1)
}
a.startRotate()
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
a.update { (vm) in
vm.scene = .error
vm.title = "同步失败"
vm.message = "请检查网络是否通畅"
vm.add(action: .default, title: "重试") {
loading()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
})
}
loading()
} else if row == 4 {
func loading(_ index: Int = 1) {
if let _ = Alert.find("loading").last {
Toast.push("loading-tip") { (t) in
t.update { (vm) in
vm.title = "此时又调用了一次相同的弹窗 x\(index)"
}
t.pulse()
}
} else {
Alert.push("loading") { (a) in
a.update { (vm) in
vm.scene = .loading
vm.title = "正在加载"
}
a.startRotate()
}
}
loadingSuccessAfter2Seconds()
}
loading(1)
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
loading(2)
}
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
loading(3)
}
DispatchQueue.main.asyncAfter(deadline: .now()+3) {
loading(4)
}
DispatchQueue.main.asyncAfter(deadline: .now()+3.5) {
loading(5)
}
DispatchQueue.main.asyncAfter(deadline: .now()+4) {
loading(6)
}
} else if row == 5 {
func f(_ i: Int) {
Alert.push() { (a) in
// MARK: 2
sec.addRow(title: "场景同步成功写法2") {
let a = Alert.push("loading") { (a) in
a.startRotate()
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步" + String(i)
vm.message = "请稍等片刻"
}
}
}
f(1)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
f(2)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
f(3)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
f(4)
}
} else if row == 6 {
Alert.push() { (a) in
a.update { (vm) in
vm.scene = .confirm
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.add(action: .default, title: "我知道了", handler: nil)
}
}
} else if row == 7 {
Alert.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.add(action: .default, title: "我知道了", handler: nil)
}
}
} else if row == 8 {
Alert.push("progress") { (a) in
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
a.startRotate()
a.update(progress: 0)
let s = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
for i in 0 ... 5 {
s.wait()
DispatchQueue.main.async {
Alert.find("progress", last: { (a) in
a.update(progress: CGFloat(i)/5)
print("\(CGFloat(i)/5)")
if i == 5 {
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
loadingSuccessAfter2Seconds()
}
// MARK:
sec.addRow(title: "场景:正在同步(更新进度)") {
Alert.push("progress") { (a) in
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
a.startRotate()
a.update(progress: 0)
let s = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
for i in 0 ... 100 {
s.wait()
DispatchQueue.main.async {
Alert.find("progress", last: { (a) in
a.update(progress: CGFloat(i)/100)
print("\(CGFloat(i)/100)")
if i == 100 {
DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
}
}
}
})
DispatchQueue.main.asyncAfter(deadline: .now()+0.03) {
s.signal()
}
})
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
s.signal()
}
}
}
}
}
// MARK:
sec.addRow(title: "场景:同步失败和重试(布局变化)") {
Alert.push("loading", scene: .loading)
func loading() {
Alert.find("loading") { (a) in
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
vm.remove(action: 0, 1)
}
a.startRotate()
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
a.update { (vm) in
vm.scene = .error
vm.title = "同步失败"
vm.message = "请检查网络是否通畅"
vm.add(action: .default, title: "重试") {
loading()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
}
}
loading()
}
sec.footer = "两种写法1和写法2动画效果略微不同"
}
vm.addSection(title: "为了解决代码逻辑疏漏导致程序卡死、弹窗重叠等问题") { (sec) in
// MARK:
sec.addRow(title: "极端场景:正在同步(超时未处理)", subtitle: "超时未处理的意外情况弹窗可以手动关闭。在config中配置所需时间") {
func f() {
Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (a) in
a.identifier = "loading"
a.startRotate()
a.didForceQuit {
let t = Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻点击展开为Alert") { (vm) in
vm.identifier = "loading"
}
t.startRotate()
t.didTapped { [weak t] in
t?.pop()
f()
}
}
}
}
f()
}
// MARK:
sec.addRow(title: "极端场景:短时间内调用了多次同一个弹窗", subtitle: "多次调用页面弹窗应该是毫无变化的。本例中4秒内调用了6次") {
func loading(_ index: Int = 1) {
if Alert.find("loading").count == 0 {
Alert.push("loading", scene: .loading) { (a) in
a.update { (vm) in
vm.title = "正在加载"
}
a.startRotate()
}
}
}
loading(1)
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
loading(2)
}
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
loading(3)
}
DispatchQueue.main.asyncAfter(deadline: .now()+3) {
loading(4)
}
DispatchQueue.main.asyncAfter(deadline: .now()+3.5) {
loading(5)
}
DispatchQueue.main.asyncAfter(deadline: .now()+4) {
loading(6)
}
}
// MARK:
sec.addRow(title: "极端场景:多个不同的弹窗重叠", subtitle: "多个弹窗不得不重叠的时候ProHUD的景深处理可以使其看起来舒服一些。") {
func f(_ i: Int) {
Alert.push() { (a) in
a.startRotate()
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步" + String(i)
vm.message = "请稍等片刻"
}
}
}
f(1)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
f(2)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
f(3)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
f(4)
}
}
}
vm.addSection(title: "") { (sec) in
// MARK:
sec.addRow(title: "测试较长的标题和内容") {
Alert.push() { (a) in
a.update { (vm) in
vm.scene = .confirm
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.add(action: .default, title: "我知道了", handler: nil)
}
}
}
// MARK:
sec.addRow(title: "测试特别长的标题和内容", subtitle: "这种情况编码阶段就可以避免,所以没有做特别处理,请控制内容长度不要过长。") {
Alert.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.add(action: .default, title: "我知道了", handler: nil)
}
}
}
// MARK:
sec.addRow(title: "只有标题") {
Alert.push(scene: .default, title: "标题")
}
// MARK:
sec.addRow(title: "只有消息") {
Alert.push(scene: .default, message: "这是消息")
}
// MARK:
sec.addRow(title: "既没有标题也没有消息") {
Alert.push("a")
}
}
}
func simulateSync() {

View File

@ -15,110 +15,115 @@ class TestGuardVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var titles: [String] {
return ["场景:删除菜单", "场景:升级至专业版", "场景:隐私协议页面", "对比原生的ActionSheet", "对比原生Present效果"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
Guard.push("del") { (vc) in
vc.update { (vm) in
vm.add(action: .destructive, title: "删除") { [weak vc] in
Alert.push(scene: .delete) { (vc) in
vc.update { (vm) in
vm.add(action: .destructive, title: "删除") { [weak vc] in
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
} else if row == 1 {
// id
Guard.push("pro") { (vc) in
vc.identifier = "pro"
vc.update { (vm) in
vm.add(title: "升级至专业版")
vm.add(subTitle: "解锁功能")
vm.add(message: "功能1功能2...")
vm.add(subTitle: "价格")
vm.add(message: "只需一次性付费$2999即可永久享用。")
vm.add(message: "只需一次性付费$2999即可永久享用。")
vm.add(action: .destructive, title: "购买") { [weak vc] in
Alert.push(scene: .buy) { (vc) in
vc.identifier = "confirm"
vc.update { (vm) in
vm.add(action: .destructive, title: "购买") { [weak vc] in
vc?.update({ (vm) in
vm.scene = .loading
vm.title = "正在付款"
vm.message = "请稍等片刻"
vm.remove(action: 0, 1)
})
vc?.startRotate()
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
vc?.update({ (vm) in
vm.scene = .success
vm.title = "购买成功"
vm.message = "感谢您的支持"
vm.add(action: .default, title: "我知道了") {
vc?.pop()
}
})
vm.addSection(title: "") { (sec) in
// MARK:
sec.addRow(title: "场景:删除菜单") {
Guard.push("del") { (vc) in
vc.update { (vm) in
vm.add(action: .destructive, title: "删除") { [weak vc] in
Alert.push(scene: .delete) { (vc) in
vc.update { (vm) in
vm.add(action: .destructive, title: "删除") { [weak vc] in
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
vc?.pop()
}
vc?.pop()
vm.add(action: .cancel, title: "取消", handler: nil)
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
} else if row == 2 {
Guard.push("license") { (vc) in
vc.isFullScreen = true
vc.update { (vm) in
let titleLabel = vm.add(title: "隐私协议")
titleLabel.snp.makeConstraints { (mk) in
mk.height.equalTo(44)
}
let tv = UITextView()
tv.backgroundColor = .white
tv.isEditable = false
vc.textStack.addArrangedSubview(tv)
tv.text = "这里可以插入一个webView"
vm.add(message: "请认真阅读以上内容,当您阅读完毕并同意协议内容时点击接受按钮。")
vm.add(action: .default, title: "接受") { [weak vc] in
vc?.pop()
// MARK:
sec.addRow(title: "场景:升级至专业版") {
// id
Guard.push("pro") { (vc) in
vc.identifier = "pro"
vc.update { (vm) in
vm.add(title: "升级至专业版")
vm.add(subTitle: "解锁功能")
vm.add(message: "功能1功能2...")
vm.add(subTitle: "价格")
vm.add(message: "只需一次性付费$2999即可永久享用。")
vm.add(message: "只需一次性付费$2999即可永久享用。")
vm.add(action: .destructive, title: "购买") { [weak vc] in
Alert.push(scene: .buy) { (vc) in
vc.identifier = "confirm"
vc.update { (vm) in
vm.add(action: .destructive, title: "购买") { [weak vc] in
vc?.update({ (vm) in
vm.scene = .loading
vm.title = "正在付款"
vm.message = "请稍等片刻"
vm.remove(action: 0, 1)
})
vc?.startRotate()
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
vc?.update({ (vm) in
vm.scene = .success
vm.title = "购买成功"
vm.message = "感谢您的支持"
vm.add(action: .default, title: "我知道了") {
vc?.pop()
}
})
}
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
}
} else if row == 3 {
let ac = UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
ac.addAction(ok)
ac.addAction(cancel)
ac.popoverPresentationController?.sourceView = tableView.cellForRow(at: indexPath)
self.present(ac, animated: true, completion: nil)
} else if row == 4 {
let vc = UIViewController()
vc.view.backgroundColor = .white
vc.title = "ceshi"
present(vc, animated: true, completion: nil)
// MARK:
sec.addRow(title: "场景:隐私协议页面") {
Guard.push("license") { (vc) in
vc.isFullScreen = true
vc.update { (vm) in
let titleLabel = vm.add(title: "隐私协议")
titleLabel.snp.makeConstraints { (mk) in
mk.height.equalTo(44)
}
let tv = UITextView()
tv.backgroundColor = .white
tv.isEditable = false
vc.textStack.addArrangedSubview(tv)
tv.text = "这里可以插入一个webView"
vm.add(message: "请认真阅读以上内容,当您阅读完毕并同意协议内容时点击接受按钮。")
vm.add(action: .default, title: "接受") { [weak vc] in
vc?.pop()
}
}
}
}
// MARK: ActionSheet
sec.addRow(title: "对比原生的ActionSheet") {
let ac = UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
ac.addAction(ok)
ac.addAction(cancel)
ac.popoverPresentationController?.sourceView = self.view
self.present(ac, animated: true, completion: nil)
}
// MARK: Present
sec.addRow(title: "对比原生Present效果") {
let vc = UIViewController()
vc.view.backgroundColor = .white
vc.title = "ceshi"
self.present(vc, animated: true, completion: nil)
}
}
}

View File

@ -9,208 +9,218 @@
import UIKit
import ProHUD
typealias Callback2 = (String) -> Void
class TestToastVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var titles: [String] {
return ["场景:正在同步",
"场景:正在同步(更新进度)",
"场景:同步成功",
"场景:同步失败",
"场景:设备电量过低",
"传入指定图标",
"禁止手势移除",
"组合使用示例",
"避免重复发布同一条信息",
"根据id查找并修改实例",
"测试较长的标题和内容",
"测试特别长的标题和内容",
"测试只有title",
"测试只有message",
"自定义旋转的图片"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
vm.identifier = "loading"
}.startRotate()
simulateSync()
} else if row == 1 {
if let _ = Toast.find("progress").last {
} else {
Toast.push("progress") { (t) in
t.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
t.startRotate()
t.update(progress: 0)
let s = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
for i in 0 ... 5 {
s.wait()
DispatchQueue.main.async {
Toast.find("progress", last: { (t) in
t.update(progress: CGFloat(i)/5)
print("\(CGFloat(i)/5)")
if i == 5 {
t.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = "xxx"
vm.addSection(title: "基本场景") { (sec) in
// MARK:
sec.addRow(title: "场景:正在同步") {
Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
vm.identifier = "loading"
}.startRotate()
self.simulateSync()
}
// MARK:
sec.addRow(title: "场景:正在同步(更新进度)") {
if Toast.find("progress").count == 0 {
Toast.push("progress") { (t) in
t.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
}
t.startRotate()
t.update(progress: 0)
let s = DispatchSemaphore(value: 1)
DispatchQueue.global().async {
for i in 0 ... 5 {
s.wait()
DispatchQueue.main.async {
Toast.find("progress", last: { (t) in
t.update(progress: CGFloat(i)/5)
print("\(CGFloat(i)/5)")
if i == 5 {
t.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = "xxx"
}
}
})
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
s.signal()
}
})
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
s.signal()
}
}
}
}
}
}
} else if row == 2 {
let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情")
t.didTapped { [weak self, weak t] in
self?.presentEmptyVC(title: "详情")
t?.pop()
}
} else if row == 3 {
Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vc) in
vc.update { (vm) in
vm.duration = 0
}
vc.didTapped { [weak self, weak vc] in
self?.presentEmptyVC(title: "这是错误详情")
vc?.pop()
// MARK:
sec.addRow(title: "场景:同步成功") {
let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情")
t.didTapped { [weak self, weak t] in
self?.presentEmptyVC(title: "详情")
t?.pop()
}
}
} else if row == 4 {
Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。")
} else if row == 5 {
Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vc) in
vc.update { (vm) in
if #available(iOS 13.0, *) {
vc.imageView.tintColor = .brown
vm.icon = UIImage(systemName: "icloud.and.arrow.down")
} else {
vm.icon = UIImage(named: "icloud.and.arrow.down")
// MARK:
sec.addRow(title: "场景:同步失败") {
Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vc) in
vc.update { (vm) in
vm.duration = 0
}
vc.didTapped { [weak self, weak vc] in
self?.presentEmptyVC(title: "这是错误详情")
vc?.pop()
}
}
}
} else if row == 6 {
Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失每次拖拽都会刷新倒计时。") { (vc) in
vc.isRemovable = false
vc.update { (vm) in
vm.duration = 5
// MARK:
sec.addRow(title: "场景:设备电量过低") {
Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vc) in
vc.update { (vm) in
if #available(iOS 13.0, *) {
vc.imageView.tintColor = .brown
vm.icon = UIImage(systemName: "icloud.and.arrow.down")
} else {
vm.icon = UIImage(named: "icloud.and.arrow.down")
}
}
}
}
} else if row == 7 {
Toast.push(scene: .message, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10) { (vc) in
vc.identifier = "xxx"
vc.didTapped { [weak vc] in
vc?.pop()
Alert.push(scene: .confirm, title: "好友邀请", message: "用户xxx想要添加你为好友是否同意") { (vc) in
vc.update { (vm) in
vm.add(action: .default, title: "接受") { [weak vc] in
vc?.pop()
Toast.push(scene: .success, title: "好友添加成功", message: "这是消息内容")
}
vm.add(action: .cancel, title: "拒绝") {
}
vm.addSection(title: "") { (sec) in
// MARK:
sec.addRow(title: "传入指定图标") {
Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。")
}
// MARK:
sec.addRow(title: "禁止手势移除") {
Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失每次拖拽都会刷新倒计时。") { (vc) in
vc.isRemovable = false
vc.update { (vm) in
vm.duration = 5
}
}
}
// MARK: 使
sec.addRow(title: "组合使用示例") {
Toast.push(scene: .message, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10) { (vc) in
vc.identifier = "xxx"
vc.didTapped { [weak vc] in
vc?.pop()
Alert.push(scene: .confirm, title: "好友邀请", message: "用户xxx想要添加你为好友是否同意") { (vc) in
vc.update { (vm) in
vm.add(action: .default, title: "接受") { [weak vc] in
vc?.pop()
Toast.push(scene: .success, title: "好友添加成功", message: "这是消息内容")
}
vm.add(action: .cancel, title: "拒绝") {
}
}
}
}
}
}
} else if row == 8 {
if let t = Toast.find("aaa").last {
t.pulse()
t.update() { (vm) in
vm.title = "已经存在了"
}
} else {
Toast.push(title: "这是一条id为aaa的横幅", message: "避免重复发布同一条信息") { (t) in
t.identifier = "aaa"
t.update { (vm) in
vm.scene = .warning
vm.duration = 0
// MARK:
sec.addRow(title: "避免重复发布同一条信息") {
if let t = Toast.find("aaa").last {
t.pulse()
t.update() { (vm) in
vm.title = "已经存在了"
}
} else {
Toast.push(title: "这是一条id为aaa的横幅", message: "避免重复发布同一条信息") { (t) in
t.identifier = "aaa"
t.update { (vm) in
vm.scene = .warning
vm.duration = 0
}
}
}
}
} else if row == 9 {
Toast.push("aaa") { (t) in
t.update { (vm) in
vm.scene = .success
vm.title = "找到了哈哈"
vm.message = "根据id查找并修改实例"
// MARK: id
sec.addRow(title: "根据id查找并修改实例") {
Toast.push("aaa") { (t) in
t.update { (vm) in
vm.scene = .success
vm.title = "找到了哈哈"
vm.message = "根据id查找并修改实例"
}
t.pulse()
}
t.pulse()
}
} else if row == 10 {
Toast.push() { (a) in
a.update { (vm) in
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
// MARK:
sec.addRow(title: "测试较长的标题和内容") {
Toast.push() { (a) in
a.update { (vm) in
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
}
}
}
} else if row == 11 {
Toast.push() { (a) in
a.update { (vm) in
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
// MARK:
sec.addRow(title: "测试特别长的标题和内容") {
Toast.push() { (a) in
a.update { (vm) in
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
}
}
}
} else if row == 12 {
Toast.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.title = "正在同步看到了你撒地"
// MARK: title
sec.addRow(title: "测试只有title") {
Toast.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.title = "正在同步看到了你撒地"
}
}
}
} else if row == 13 {
Toast.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
// MARK: message
sec.addRow(title: "测试只有message") {
Toast.push() { (a) in
a.update { (vm) in
vm.scene = .warning
vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
}
}
}
} else if row == 14 {
Toast.push(scene: .privacy, title: "正在授权", message: "请稍等片刻") { (t) in
t.identifier = "loading"
let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle"))
t.imageView.addSubview(imgv)
imgv.snp.makeConstraints { (mk) in
mk.center.equalToSuperview()
mk.width.height.equalTo(18)
// MARK:
sec.addRow(title: "自定义旋转的图片") {
Toast.push(scene: .privacy, title: "正在授权", message: "请稍等片刻") { (t) in
t.identifier = "loading"
let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle"))
t.imageView.addSubview(imgv)
imgv.snp.makeConstraints { (mk) in
mk.center.equalToSuperview()
mk.width.height.equalTo(18)
}
t.startRotate(imgv.layer, speed: 4)
}
t.startRotate(imgv.layer, speed: 4)
self.simulateSync()
}
simulateSync()
}
}
func simulateSync() {
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
Toast.find("loading", last: { (t) in
t.update { (vm) in
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
Toast.find("loading", last: { (a) in
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = "啊哈哈哈哈哈哈哈哈"

View File

@ -16,27 +16,25 @@ class ViewController: BaseListVC {
super.viewDidLoad()
// Do any additional setup after loading the view.
title = "\(Bundle.main.infoDictionary?["CFBundleName"] ?? "ProHUD")"
}
override var titles: [String] {
return ["Toast", "Alert", "Guard"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
let vc = TestToastVC()
vc.title = titles[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
} else if indexPath.row == 1 {
let vc = TestAlertVC()
vc.title = titles[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
} else {
let vc = TestGuardVC()
vc.title = titles[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
vm.addSection(title: "") { (sec) in
sec.addRow(title: "Toast") {
let vc = TestToastVC()
vc.title = "Toast"
self.navigationController?.pushViewController(vc, animated: true)
}
sec.addRow(title: "Alert") {
let vc = TestAlertVC()
vc.title = "Alert"
self.navigationController?.pushViewController(vc, animated: true)
}
sec.addRow(title: "Guard") {
let vc = TestGuardVC()
vc.title = "Guard"
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
}

View File

@ -63,10 +63,10 @@ public extension ProHUD {
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) {
public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) {
self.init()
vm.vc = self
vm.scene = scene
vm.scene = scene ?? .default
vm.title = title
vm.message = message
actions?(self)
@ -148,7 +148,7 @@ public extension Alert {
}
///
///
/// - Parameter callback:
func didForceQuit(_ callback: (() -> Void)?) {
vm.forceQuitCallback = callback
@ -177,14 +177,19 @@ public extension Alert {
/// - identifier:
/// - toast:
/// - Returns:
@discardableResult class func push(_ identifier: String, instance: @escaping (Alert) -> Void) -> Alert {
@discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Alert) -> Void)? = nil) -> Alert {
if let a = find(identifier).last {
instance(a)
if let s = scene, s != a.vm.scene {
a.update { (vm) in
vm.scene = s
}
}
instance?(a)
return a
} else {
return Alert() { (aa) in
return Alert(scene: scene) { (aa) in
aa.identifier = identifier
instance(aa)
instance?(aa)
}.push()
}
}

View File

@ -75,11 +75,11 @@ public extension ProHUD {
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, duration: TimeInterval? = nil, actions: ((Toast) -> Void)? = nil) {
public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, icon: UIImage? = nil, duration: TimeInterval? = nil, actions: ((Toast) -> Void)? = nil) {
self.init()
vm.vc = self
vm.scene = scene
vm.scene = scene ?? .default
vm.title = title
vm.message = message
vm.icon = icon
@ -227,14 +227,19 @@ public extension Toast {
/// - identifier:
/// - toast:
/// - Returns:
@discardableResult class func push(_ identifier: String, instance: @escaping (Toast) -> Void) -> Toast {
@discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Toast) -> Void)? = nil) -> Toast {
if let t = find(identifier).last {
instance(t)
if let s = scene, s != t.vm.scene {
t.update { (vm) in
vm.scene = s
}
}
instance?(t)
return t
} else {
return Toast() { (tt) in
return Toast(scene: scene) { (tt) in
tt.identifier = identifier
instance(tt)
instance?(tt)
}.push()
}
}