mirror of https://github.com/xaoxuu/ProHUD
update
This commit is contained in:
parent
1da5242844
commit
3639558a9c
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "IMG_0564.PNG",
|
||||
"filename" : "IMG_099256E14955-1.jpeg",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 530 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
|
@ -19,6 +19,14 @@
|
|||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" image="bg" translatesAutoresizingMaskIntoConstraints="NO" id="0oA-CL-uZS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PcH-Px-Vql">
|
||||
<rect key="frame" x="51" y="120" width="46" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="Button"/>
|
||||
<connections>
|
||||
<action selector="test:" destination="BYZ-38-t0r" eventType="touchUpInside" id="mff-h5-exz"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
|
|
|
@ -17,27 +17,77 @@ class ViewController: UIViewController {
|
|||
|
||||
|
||||
ProHUD.configAlert { (alert) in
|
||||
alert.minimizeTimeout = 5
|
||||
alert.minimizeTimeout = 3
|
||||
|
||||
}
|
||||
ProHUD.configGuard { (g) in
|
||||
g.tintColor = .success
|
||||
}
|
||||
ProHUD.configToast { (toast) in
|
||||
// toast.backgroundColorForScene { (scene) -> UIColor? in
|
||||
// return UIColor.yellow
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
func testToast() {
|
||||
let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻")
|
||||
|
||||
let a = ProHUD.show(alert : .loading, title: "正在加载", message: "请稍候片刻")
|
||||
a.didMinimize {
|
||||
hud.show(t)
|
||||
}
|
||||
t.didTapped { [weak t] in
|
||||
t?.remove()
|
||||
let a2 = ProHUD.show(alert: .loading, title: "正在加载", message: "马上就要成功了")
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
|
||||
let a3 = ProHUD.show(alert: .error, title: "加载失败", message: "点击充实")
|
||||
a3.addAction(style: .default, title: "重新加载") { [weak a3] in
|
||||
a3?.updateContent(scene: .success, title: "加载成功", message: "马上就要成功了")
|
||||
a3?.updateAction(index: 0, style: .default, title: "OK", action: { [weak a2, a3] in
|
||||
a2?.remove()
|
||||
a3?.remove()
|
||||
}).removeAction(index: 1).removeAction(index: 1)
|
||||
}.addAction(style: .destructive, title: "终止", action: nil).addAction(style: .cancel, title: "取消", action: nil)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func testDelete() {
|
||||
let a = ProHUD.show(alert: .delete, title: "确认删除", message: "此操作不可撤销")
|
||||
a.addAction(style: .destructive, title: "确认", action: { [weak a] in
|
||||
a?.removeAction(index: 0).removeAction(index: 0)
|
||||
a?.updateContent(scene: .loading, title: "正在删除", message: "请稍后片刻")
|
||||
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
|
||||
a?.updateContent(scene: .success, title: "删除成功", message: "啊哈哈哈哈").timeout(2)
|
||||
a?.addAction(style: .default, title: "我知道了", action: {
|
||||
// a?.remove()
|
||||
a?.removeAction(index: 0)
|
||||
})
|
||||
ProHUD.show(toast: .success, title: "删除成功", message: "aaa")
|
||||
}
|
||||
}).addAction(style: .cancel, title: "取消", action: nil)
|
||||
}
|
||||
|
||||
@IBAction func test(_ sender: UIButton) {
|
||||
let g = ProHUD.Guard(title: "请求权限", message: "请打开相机权限开关,否则无法进行测量。")
|
||||
// g.view.tintColor = .warning
|
||||
// g.loadBody(g.description)
|
||||
|
||||
g.loadButton(style: .default, title: "测试弹窗", action: { [weak self] in
|
||||
self?.testToast()
|
||||
})
|
||||
g.loadButton(style: .destructive, title: "测试删除弹窗", action: { [weak self] in
|
||||
self?.testDelete()
|
||||
})
|
||||
g.loadButton(style: .cancel, title: "我知道了")
|
||||
g.push(to: self)
|
||||
debugPrint("test: ", g)
|
||||
|
||||
}
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// ProHUD.show(alert: .loading, title: "确认删除", message: "此操作不可撤销").timeout(nil)
|
||||
|
@ -63,28 +113,7 @@ class ViewController: UIViewController {
|
|||
//
|
||||
// }
|
||||
|
||||
// let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻")
|
||||
//
|
||||
// let a = ProHUD.show(alert : .loading, title: "正在加载", message: "请稍候片刻")
|
||||
// a.didMinimize {
|
||||
// hud.show(t)
|
||||
// }
|
||||
// t.didTapped { [weak t] in
|
||||
// t?.remove()
|
||||
// let a2 = ProHUD.show(alert: .loading, title: "正在加载", message: "马上就要成功了")
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
|
||||
// let a3 = ProHUD.show(alert: .error, title: "加载失败", message: "点击充实")
|
||||
// a3.addAction(style: .default, title: "重新加载") { [weak a3] in
|
||||
// a3?.updateContent(scene: .success, title: "加载成功", message: "马上就要成功了")
|
||||
// a3?.updateAction(index: 0, style: .default, title: "OK", action: { [weak a2, a3] in
|
||||
// a2?.remove()
|
||||
// a3?.remove()
|
||||
// }).removeAction(index: 1).removeAction(index: 1)
|
||||
// }.addAction(style: .destructive, title: "终止", action: nil).addAction(style: .cancel, title: "取消", action: nil)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// ProHUD.show(toast: .loading, title: "正在加载", message: "拉升的反馈老实交代分开就撒开了击快乐圣反馈老实交代分开就撒开了击快乐圣")
|
||||
|
|
|
@ -31,7 +31,7 @@ public extension ProHUD.Configuration {
|
|||
/// 标题字体
|
||||
public var titleFont = UIFont.boldSystemFont(ofSize: 22)
|
||||
/// 标题颜色
|
||||
public var titleColor = UIColor(white: 0.2, alpha: 1)
|
||||
public var titleColor = UIColorForPrimaryLabel
|
||||
/// 标题最多行数
|
||||
public var titleMaxLines = Int(1)
|
||||
|
||||
|
@ -41,7 +41,7 @@ public extension ProHUD.Configuration {
|
|||
/// 正文字体
|
||||
public var bodyFont = UIFont.systemFont(ofSize: 17)
|
||||
/// 正文颜色
|
||||
public var bodyColor = UIColor.darkGray
|
||||
public var bodyColor = UIColorForSecondaryLabel
|
||||
/// 正文最多行数
|
||||
public var bodyMaxLines = Int(5)
|
||||
|
||||
|
@ -232,7 +232,7 @@ public extension ProHUD.Configuration {
|
|||
lazy var showNavButtons: (ProHUD.Alert, Alert) -> Void = {
|
||||
return { (vc, config) in
|
||||
debugPrint(vc, "showNavButtons")
|
||||
let btn = UIButton.minimizeButton()
|
||||
let btn = ProHUD.Alert.Button.minimizeButton()
|
||||
let bg = ProHUD.BlurView()
|
||||
bg.layer.masksToBounds = true
|
||||
bg.layer.cornerRadius = config.cornerRadius
|
||||
|
|
|
@ -116,31 +116,17 @@ public extension ProHUD {
|
|||
/// - Parameter text: 标题
|
||||
/// - Parameter action: 事件
|
||||
@discardableResult public func addAction(style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> Alert {
|
||||
return addAction(custom: UIButton.actionButton(style: style, title: title), action: action)
|
||||
if let btn = privAddButton(custom: Button.actionButton(title: title), action: action) as? Button {
|
||||
btn.update(style: style)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
/// 添加按钮
|
||||
/// - Parameter button: 按钮
|
||||
/// - Parameter action: 事件
|
||||
@discardableResult public func addAction(custom button: UIButton , action: (() -> Void)?) -> Alert {
|
||||
timeout = nil
|
||||
if actionStack.superview == nil {
|
||||
contentStack.addArrangedSubview(actionStack)
|
||||
}
|
||||
self.view.layoutIfNeeded()
|
||||
button.transform = .init(scaleX: 1, y: 0.001)
|
||||
actionStack.addArrangedSubview(button)
|
||||
UIView.animateForAlert {
|
||||
button.transform = .identity
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
addTouchUpAction(for: button) { [weak self] in
|
||||
action?()
|
||||
if button.tag == UIAlertAction.Style.cancel.rawValue {
|
||||
self?.remove()
|
||||
}
|
||||
}
|
||||
willLayoutSubviews()
|
||||
@discardableResult public func addAction(custom button: UIButton, action: (() -> Void)?) -> Alert {
|
||||
privAddButton(custom: button, action: action)
|
||||
return self
|
||||
}
|
||||
|
||||
|
@ -178,7 +164,9 @@ public extension ProHUD {
|
|||
@discardableResult public func updateAction(index: Int, style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> Alert {
|
||||
return updateAction(index: index, button: { (btn) in
|
||||
btn.setTitle(title, for: .normal)
|
||||
btn.update(style: style)
|
||||
if let b = btn as? Button {
|
||||
b.update(style: style)
|
||||
}
|
||||
btn.layoutIfNeeded()
|
||||
}, action: action)
|
||||
}
|
||||
|
@ -254,6 +242,27 @@ fileprivate extension ProHUD.Alert {
|
|||
DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willLayout!)
|
||||
}
|
||||
|
||||
@discardableResult private func privAddButton(custom button: UIButton, action: (() -> Void)?) -> UIButton {
|
||||
timeout = nil
|
||||
if actionStack.superview == nil {
|
||||
contentStack.addArrangedSubview(actionStack)
|
||||
}
|
||||
self.view.layoutIfNeeded()
|
||||
button.transform = .init(scaleX: 1, y: 0.001)
|
||||
actionStack.addArrangedSubview(button)
|
||||
UIView.animateForAlert {
|
||||
button.transform = .identity
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
addTouchUpAction(for: button) { [weak self] in
|
||||
action?()
|
||||
if button.tag == UIAlertAction.Style.cancel.rawValue {
|
||||
self?.remove()
|
||||
}
|
||||
}
|
||||
willLayoutSubviews()
|
||||
return button
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -8,59 +8,48 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
public extension ProHUD.Alert {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension UIButton {
|
||||
|
||||
class func actionButton(style: UIAlertAction.Style, title: String?) -> UIButton {
|
||||
let btn = UIButton(type: .system)
|
||||
btn.setTitle(title, for: .normal)
|
||||
btn.layer.cornerRadius = alertConfig.cornerRadius / 2
|
||||
btn.titleLabel?.font = alertConfig.buttonFont
|
||||
btn.update(style: style)
|
||||
return btn
|
||||
}
|
||||
|
||||
func update(style: UIAlertAction.Style) {
|
||||
let pd = alertConfig.padding/2
|
||||
if style != .cancel {
|
||||
backgroundColor = .init(white: 0, alpha: 0.04)
|
||||
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
|
||||
} else {
|
||||
contentEdgeInsets = .init(top: pd*0.5, left: pd*1.5, bottom: pd*0.5, right: pd*1.5)
|
||||
internal extension ProHUD.Alert {
|
||||
class Button: UIButton {
|
||||
class func actionButton(title: String?) -> UIButton {
|
||||
let btn = Button(type: .system)
|
||||
btn.setTitle(title, for: .normal)
|
||||
btn.layer.cornerRadius = alertConfig.cornerRadius / 2
|
||||
btn.titleLabel?.font = alertConfig.buttonFont
|
||||
return btn
|
||||
}
|
||||
|
||||
func update(style: UIAlertAction.Style) {
|
||||
let pd = CGFloat(8)
|
||||
if style != .cancel {
|
||||
backgroundColor = dynamicColor.withAlphaComponent(0.04)
|
||||
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
|
||||
} else {
|
||||
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(UIColorForSecondaryLabel, for: .normal)
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
tag = style.rawValue
|
||||
}
|
||||
|
||||
class func minimizeButton() -> UIButton {
|
||||
let btn = Button(type: .system)
|
||||
let pd = alertConfig.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.setTitle(alertConfig.minimizeTitle, for: .normal)
|
||||
btn.setTitleColor(UIColor(red:1.00, green:0.55, blue:0.21, alpha:1.00), for: .normal)
|
||||
btn.titleLabel?.font = alertConfig.buttonFont
|
||||
return btn
|
||||
}
|
||||
switch style {
|
||||
case .default:
|
||||
setTitleColor(alertConfig.tintColor, for: .normal)
|
||||
case .destructive:
|
||||
setTitleColor(.init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1), for: .normal)
|
||||
case .cancel:
|
||||
setTitleColor(.darkGray, for: .normal)
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
tag = style.rawValue
|
||||
}
|
||||
|
||||
class func minimizeButton() -> UIButton {
|
||||
let btn = UIButton(type: .system)
|
||||
// btn.contentEdgeInsets = .init(top: 8, left: 8, bottom: 8, right: 8)
|
||||
let pd = alertConfig.padding/2
|
||||
btn.contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
|
||||
// btn.imageEdgeInsets.left = pd*0.75
|
||||
btn.imageEdgeInsets.right = pd*1.5
|
||||
// btn.setImage(ProHUD.image(named: "ProHUDMinimize"), for: .normal)
|
||||
// btn.layer.shadowOpacity = 0.15
|
||||
// btn.layer.shadowOffset = .init(width: 0, height: 1.2)
|
||||
// btn.layer.shadowRadius = 1.2
|
||||
btn.setTitle(alertConfig.minimizeTitle, for: .normal)
|
||||
btn.setTitleColor(UIColor(red:1.00, green:0.55, blue:0.21, alpha:1.00), for: .normal)
|
||||
btn.titleLabel?.font = alertConfig.buttonFont
|
||||
|
||||
return btn
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,54 +7,149 @@
|
|||
//
|
||||
|
||||
import SnapKit
|
||||
import Inspire
|
||||
|
||||
public extension ProHUD.Configuration {
|
||||
struct Guard {
|
||||
// MARK: 卡片样式
|
||||
/// 最大宽度(用于优化横屏或者iPad显示)
|
||||
public var maxWidth = CGFloat(556)
|
||||
/// 标题字体
|
||||
public var titleFont = UIFont.boldSystemFont(ofSize: 18)
|
||||
/// 正文字体
|
||||
public var bodyFont = UIFont.systemFont(ofSize: 16)
|
||||
/// 标题最多行数(0代表不限制)
|
||||
public var titleMaxLines = Int(0)
|
||||
/// 正文最多行数(0代表不限制)
|
||||
public var bodyMaxLines = Int(0)
|
||||
/// 圆角半径
|
||||
public var cornerRadius = CGFloat(16)
|
||||
public var cardMaxWidth = CGFloat(460)
|
||||
/// 圆角半径(手机竖屏时为0)
|
||||
public var cardCornerRadius = CGFloat(16)
|
||||
|
||||
/// 余量:元素与元素之间的距离
|
||||
public var margin = CGFloat(8)
|
||||
|
||||
/// 填充:元素内部控件距离元素边界的距离
|
||||
public var padding = CGFloat(16)
|
||||
|
||||
public var iconSize = CGSize(width: 48, height: 48)
|
||||
// MARK: 图标样式
|
||||
/// 颜色
|
||||
public var tintColor: UIColor?
|
||||
|
||||
// MARK: 文本样式
|
||||
/// 标题字体
|
||||
public var titleFont = UIFont.boldSystemFont(ofSize: 22)
|
||||
/// 标题颜色
|
||||
public var titleColor = UIColorForPrimaryLabel
|
||||
|
||||
/// 正文字体
|
||||
public var bodyFont = UIFont.systemFont(ofSize: 18)
|
||||
/// 正文颜色
|
||||
public var bodyColor = UIColorForSecondaryLabel
|
||||
|
||||
// MARK: 按钮样式
|
||||
/// 按钮字体
|
||||
public var buttonFont = UIFont.boldSystemFont(ofSize: 18)
|
||||
/// 按钮最大宽度(用于优化横屏或者iPad显示)
|
||||
// public var buttonMaxWidth = CGFloat(460)
|
||||
/// 按钮圆角半径
|
||||
public var buttonCornerRadius = CGFloat(12)
|
||||
|
||||
lazy var loadTitleLabel: (ProHUD.Guard, Guard) -> Void = {
|
||||
return { (vc, config) in
|
||||
debugPrint(vc, "loadTitleLabel")
|
||||
if vc.titleLabel == nil {
|
||||
vc.titleLabel = UILabel()
|
||||
vc.titleLabel?.font = config.titleFont
|
||||
vc.titleLabel?.textColor = config.titleColor
|
||||
vc.titleLabel?.numberOfLines = 0
|
||||
vc.titleLabel?.textAlignment = .justified
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
lazy var loadBodyLabel: (ProHUD.Guard, Guard) -> Void = {
|
||||
return { (vc, config) in
|
||||
debugPrint(vc, "loadBodyLabel")
|
||||
if vc.bodyLabel == nil {
|
||||
vc.bodyLabel = UILabel()
|
||||
vc.bodyLabel?.font = config.bodyFont
|
||||
vc.bodyLabel?.textColor = config.bodyColor
|
||||
vc.bodyLabel?.numberOfLines = 0
|
||||
vc.titleLabel?.textAlignment = .justified
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
/// 加载视图
|
||||
lazy var loadSubviews: (ProHUD.Alert) -> Void = {
|
||||
return { (vc) in
|
||||
lazy var loadSubviews: (ProHUD.Guard, Guard) -> Void = {
|
||||
return { (vc, config) in
|
||||
debugPrint(vc, "loadSubviews")
|
||||
// background
|
||||
vc.view.tintColor = config.tintColor
|
||||
vc.view.backgroundColor = UIColor(white: 0, alpha: 0)
|
||||
vc.view.addSubview(vc.contentView)
|
||||
var width = UIScreen.main.bounds.width
|
||||
if width > config.cardMaxWidth {
|
||||
// 横屏或者iPad
|
||||
width = config.cardMaxWidth
|
||||
vc.contentView.layer.masksToBounds = true
|
||||
vc.contentView.layer.cornerRadius = config.cardCornerRadius
|
||||
} else {
|
||||
vc.contentView.layer.shadowRadius = 4
|
||||
vc.contentView.layer.shadowOffset = .init(width: 0, height: 2)
|
||||
vc.contentView.layer.shadowOpacity = 0.12
|
||||
}
|
||||
vc.contentView.snp.makeConstraints { (mk) in
|
||||
mk.centerX.equalToSuperview()
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
if width == config.cardMaxWidth {
|
||||
mk.bottom.equalToSuperview().offset(-Inspire.shared.screen.safeAreaInsets.bottom)
|
||||
} else {
|
||||
mk.bottom.equalToSuperview()
|
||||
}
|
||||
} else if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
mk.centerY.equalToSuperview()
|
||||
}
|
||||
mk.width.equalTo(width)
|
||||
}
|
||||
// stack
|
||||
vc.contentView.contentView.addSubview(vc.contentStack)
|
||||
vc.contentStack.snp.makeConstraints { (mk) in
|
||||
mk.top.equalToSuperview().offset(config.padding + config.margin)
|
||||
mk.centerX.equalToSuperview()
|
||||
if width == config.cardMaxWidth {
|
||||
mk.bottom.equalToSuperview().offset(-config.padding)
|
||||
} else {
|
||||
mk.bottom.equalToSuperview().offset(-config.margin-Inspire.shared.screen.safeAreaInsets.bottom)
|
||||
}
|
||||
if isPortrait {
|
||||
mk.width.equalToSuperview().offset(-config.padding * 2)
|
||||
} else {
|
||||
mk.width.equalToSuperview().offset(-config.padding * 4)
|
||||
}
|
||||
}
|
||||
vc.contentStack.addArrangedSubview(vc.textStack)
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
/// 更新视图
|
||||
lazy var updateFrame: (ProHUD.Alert) -> Void = {
|
||||
return { (vc) in
|
||||
lazy var updateFrame: (ProHUD.Guard, Guard) -> Void = {
|
||||
return { (vc, config) in
|
||||
debugPrint(vc, "updateFrame")
|
||||
}
|
||||
}()
|
||||
|
||||
/// 加载视图
|
||||
/// - Parameter callback: 回调代码
|
||||
public mutating func loadSubviews(_ callback: @escaping (ProHUD.Alert) -> Void) {
|
||||
public mutating func loadSubviews(_ callback: @escaping (ProHUD.Guard, Guard) -> Void) {
|
||||
loadSubviews = callback
|
||||
}
|
||||
|
||||
/// 更新视图
|
||||
/// - Parameter callback: 回调代码
|
||||
public mutating func updateFrame(_ callback: @escaping (ProHUD.Alert) -> Void) {
|
||||
public mutating func updateFrame(_ callback: @escaping (ProHUD.Guard, Guard) -> Void) {
|
||||
updateFrame = callback
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal var guardConfig = ProHUD.Configuration.Guard()
|
||||
|
||||
public extension ProHUD {
|
||||
static func configGuard(_ config: (inout Configuration.Guard) -> Void) {
|
||||
config(&guardConfig)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,193 @@
|
|||
// Copyright © 2019 Titan Studio. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SnapKit
|
||||
|
||||
public extension ProHUD {
|
||||
class Guard: HUDController {
|
||||
|
||||
/// 内容容器
|
||||
public var contentView = BlurView()
|
||||
|
||||
/// 内容容器(包括textStack、actionStack)
|
||||
public var contentStack: StackContainer = {
|
||||
let stack = StackContainer()
|
||||
stack.spacing = guardConfig.padding + guardConfig.margin
|
||||
stack.alignment = .fill
|
||||
return stack
|
||||
}()
|
||||
|
||||
/// 文本区域
|
||||
public var textStack: StackContainer = {
|
||||
let stack = StackContainer()
|
||||
stack.spacing = guardConfig.margin
|
||||
stack.alignment = .fill
|
||||
return stack
|
||||
}()
|
||||
|
||||
public var titleLabel: UILabel?
|
||||
public var bodyLabel: UILabel?
|
||||
|
||||
/// 操作区域
|
||||
public var actionStack: StackContainer = {
|
||||
let stack = StackContainer()
|
||||
stack.alignment = .fill
|
||||
stack.spacing = guardConfig.margin
|
||||
return stack
|
||||
}()
|
||||
|
||||
/// 是否是强制性的(点击空白处是否可以消失)
|
||||
public var force = false
|
||||
|
||||
private let tag = Int(23905340)
|
||||
|
||||
private var displaying = false
|
||||
// MARK: 生命周期
|
||||
|
||||
/// 实例化
|
||||
/// - Parameter scene: 场景
|
||||
/// - Parameter title: 标题
|
||||
/// - Parameter message: 内容
|
||||
/// - Parameter icon: 图标
|
||||
public convenience init(title: String? = nil, message: String? = nil) {
|
||||
self.init()
|
||||
view = View()
|
||||
view.tintColor = guardConfig.tintColor
|
||||
if let _ = title {
|
||||
loadTitle(title)
|
||||
}
|
||||
if let _ = message {
|
||||
loadBody(message)
|
||||
}
|
||||
guardConfig.loadSubviews(self, guardConfig)
|
||||
// willLayoutSubviews()
|
||||
|
||||
// 点击
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:)))
|
||||
view.addGestureRecognizer(tap)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint(self, "deinit")
|
||||
}
|
||||
|
||||
public func push(to viewController: UIViewController? = nil) {
|
||||
if let vc = viewController {
|
||||
view.layoutIfNeeded()
|
||||
vc.addChild(self)
|
||||
vc.view.addSubview(view)
|
||||
view.isUserInteractionEnabled = true
|
||||
view.snp.makeConstraints { (mk) in
|
||||
mk.edges.equalToSuperview()
|
||||
}
|
||||
if displaying == false {
|
||||
translateOut()
|
||||
}
|
||||
displaying = true
|
||||
UIView.animateForGuard {
|
||||
self.translateIn()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func pop() {
|
||||
if displaying {
|
||||
debugPrint("pop")
|
||||
displaying = false
|
||||
view.isUserInteractionEnabled = false
|
||||
self.removeFromParent()
|
||||
UIView.animateForGuard(animations: {
|
||||
self.translateOut()
|
||||
}) { (done) in
|
||||
if self.displaying == false {
|
||||
self.view.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension ProHUD.Guard {
|
||||
|
||||
@discardableResult
|
||||
func loadTitle(_ text: String?) -> UILabel {
|
||||
guardConfig.loadTitleLabel(self, guardConfig)
|
||||
let lb = titleLabel!
|
||||
lb.text = text
|
||||
if textStack.arrangedSubviews.count > 0 {
|
||||
textStack.insertArrangedSubview(lb, at: 0)
|
||||
} else {
|
||||
textStack.addArrangedSubview(lb)
|
||||
}
|
||||
return lb
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func loadBody(_ text: String?) -> UILabel {
|
||||
guardConfig.loadBodyLabel(self, guardConfig)
|
||||
let lb = bodyLabel!
|
||||
lb.text = text
|
||||
textStack.addArrangedSubview(lb)
|
||||
return lb
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func loadButton(style: UIAlertAction.Style, title: String?, action: (() -> Void)? = nil) -> UIButton {
|
||||
let btn = Button.actionButton(title: title)
|
||||
btn.titleLabel?.font = guardConfig.buttonFont
|
||||
if actionStack.superview == nil {
|
||||
contentStack.addArrangedSubview(actionStack)
|
||||
}
|
||||
actionStack.addArrangedSubview(btn)
|
||||
btn.update(style: style)
|
||||
addTouchUpAction(for: btn) { [weak self] in
|
||||
action?()
|
||||
if btn.tag == UIAlertAction.Style.cancel.rawValue {
|
||||
self?.pop()
|
||||
}
|
||||
}
|
||||
return btn
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension ProHUD.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 translateIn() {
|
||||
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
|
||||
contentView.transform = .identity
|
||||
}
|
||||
|
||||
func translateOut() {
|
||||
view.backgroundColor = UIColor(white: 0, alpha: 0)
|
||||
contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + guardConfig.margin)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,23 @@
|
|||
// Copyright © 2019 Titan Studio. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
public extension ProHUD.Guard {
|
||||
|
||||
struct ViewModel {
|
||||
|
||||
/// 标题
|
||||
public var title: String?
|
||||
|
||||
/// 正文
|
||||
public var message: String?
|
||||
|
||||
public init(title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
|
||||
self.title = title
|
||||
self.message = message
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,69 @@
|
|||
// Copyright © 2019 Titan Studio. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
internal extension ProHUD.Guard {
|
||||
class View: UIView {
|
||||
|
||||
override func willMove(toSuperview newSuperview: UIView?) {
|
||||
if let sv = newSuperview {
|
||||
for v in sv.subviews {
|
||||
if let vv = v as? ProHUD.Guard.View {
|
||||
if vv.tag == self.tag {
|
||||
UIView.animate(withDuration: 0.38, delay: 0.1, options: .curveEaseIn, animations: {
|
||||
vv.alpha = 0
|
||||
}) { (done) in
|
||||
vv.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// override func didMoveToSuperview() {
|
||||
// if let _ = superview {
|
||||
// snp.makeConstraints { (mk) in
|
||||
//// mk.left.right.bottom.equalToSuperview()
|
||||
// mk.edges.equalToSuperview()
|
||||
// }
|
||||
//// push(duration: duration)
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
class Button: UIButton {
|
||||
class func actionButton(title: String?) -> Button {
|
||||
let btn = Button(type: .system)
|
||||
btn.setTitle(title, for: .normal)
|
||||
btn.layer.cornerRadius = guardConfig.buttonCornerRadius
|
||||
btn.titleLabel?.font = guardConfig.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(UIColorForSecondaryLabel, for: .normal)
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
tag = style.rawValue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,15 @@ public extension ProHUD {
|
|||
|
||||
|
||||
init() {
|
||||
super.init(effect: UIBlurEffect(style: .light))
|
||||
backgroundColor = UIColor.init(white: 1, alpha: 0.66)
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
super.init(effect: UIBlurEffect(style: .systemMaterial))
|
||||
// backgroundColor = UIColor.init(white: 1, alpha: 0.3)
|
||||
} else {
|
||||
super.init(effect: UIBlurEffect(style: .extraLight))
|
||||
backgroundColor = UIColor.init(white: 1, alpha: 0.66)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -96,4 +103,11 @@ internal extension UIView {
|
|||
animateEaseOut(duration: 1, delay: 0, animations: animations, completion: completion)
|
||||
}
|
||||
|
||||
class func animateForGuard(animations: @escaping () -> Void) {
|
||||
animateForGuard(animations: animations, completion: nil)
|
||||
}
|
||||
|
||||
class func animateForGuard(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
|
||||
animateEaseOut(duration: 0.6, delay: 0, animations: animations, completion: completion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,3 +48,56 @@ internal var isPortrait: Bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal var dynamicColor: UIColor {
|
||||
if #available(iOS 13.0, *) {
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .white
|
||||
} else {
|
||||
return .black
|
||||
}
|
||||
}
|
||||
return color
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
return .init(white: 0.2, alpha: 1)
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal var UIColorForPrimaryLabel: UIColor {
|
||||
return dynamicColor.withAlphaComponent(0.75)
|
||||
}
|
||||
internal var UIColorForSecondaryLabel: UIColor {
|
||||
return dynamicColor.withAlphaComponent(0.6)
|
||||
}
|
||||
|
||||
internal extension UIColor {
|
||||
|
||||
var dynamicColor: UIColor {
|
||||
if #available(iOS 13.0, *) {
|
||||
let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in
|
||||
if traitCollection.userInterfaceStyle == .dark {
|
||||
return .white
|
||||
} else {
|
||||
return .black
|
||||
}
|
||||
}
|
||||
return color
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
return .init(white: 0.2, alpha: 1)
|
||||
}
|
||||
|
||||
var dynamicPrimaryLabelColor: UIColor {
|
||||
return dynamicColor.withAlphaComponent(0.75)
|
||||
}
|
||||
var dynamicSecondaryLabelColor: UIColor {
|
||||
return dynamicColor.withAlphaComponent(0.6)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,10 +29,12 @@ public extension ProHUD.Configuration {
|
|||
|
||||
public var iconSize = CGSize(width: 48, height: 48)
|
||||
|
||||
public var tintColor: UIColor?
|
||||
/// 加载视图
|
||||
lazy var loadSubviews: (ProHUD.Toast) -> Void = {
|
||||
return { (vc) in
|
||||
debugPrint(vc, "loadSubviews")
|
||||
vc.view.tintColor = toastConfig.tintColor
|
||||
vc.view.addSubview(vc.titleLabel)
|
||||
vc.view.addSubview(vc.bodyLabel)
|
||||
vc.view.addSubview(vc.imageView)
|
||||
|
@ -64,11 +66,10 @@ public extension ProHUD.Configuration {
|
|||
}
|
||||
let img = vc.vm.icon ?? ProHUD.image(named: imgStr)
|
||||
vc.imageView.image = img
|
||||
vc.titleLabel.textColor = UIColorForPrimaryLabel
|
||||
vc.titleLabel.text = vc.vm.title
|
||||
vc.bodyLabel.textColor = UIColorForSecondaryLabel
|
||||
vc.bodyLabel.text = vc.vm.message
|
||||
|
||||
vc.tintColor = vc.vm.scene.tintColor
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -77,7 +78,6 @@ public extension ProHUD.Configuration {
|
|||
return { (vc) in
|
||||
debugPrint(vc, "layoutSubviews")
|
||||
let config = toastConfig
|
||||
|
||||
let scene = vc.vm.scene
|
||||
|
||||
vc.imageView.snp.makeConstraints { (mk) in
|
||||
|
@ -97,16 +97,7 @@ public extension ProHUD.Configuration {
|
|||
mk.leading.trailing.equalTo(vc.titleLabel)
|
||||
mk.bottom.lessThanOrEqualToSuperview().offset(-config.padding)
|
||||
}
|
||||
if [.default, .loading].contains(vc.vm.scene) {
|
||||
vc.blurMask(.extraLight)
|
||||
} else {
|
||||
vc.blurMask(nil)
|
||||
}
|
||||
if let bv = vc.blurView {
|
||||
vc.backgroundView = bv
|
||||
} else {
|
||||
vc.backgroundView.backgroundColor = vc.vm.scene.backgroundColor
|
||||
}
|
||||
|
||||
vc.view.layoutIfNeeded()
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -24,7 +24,7 @@ public extension ProHUD {
|
|||
/// 标题
|
||||
internal lazy var titleLabel: UILabel = {
|
||||
let lb = UILabel()
|
||||
lb.textColor = UIColor.init(white: 0.2, alpha: 1)
|
||||
lb.textColor = UIColorForPrimaryLabel
|
||||
lb.font = toastConfig.titleFont
|
||||
lb.textAlignment = .justified
|
||||
lb.numberOfLines = toastConfig.titleMaxLines
|
||||
|
@ -34,27 +34,25 @@ public extension ProHUD {
|
|||
/// 正文
|
||||
internal lazy var bodyLabel: UILabel = {
|
||||
let lb = UILabel()
|
||||
lb.textColor = .darkGray
|
||||
lb.textColor = UIColorForSecondaryLabel
|
||||
lb.font = toastConfig.bodyFont
|
||||
lb.textAlignment = .justified
|
||||
lb.numberOfLines = toastConfig.bodyMaxLines
|
||||
return lb
|
||||
}()
|
||||
|
||||
/// 毛玻璃层
|
||||
var blurView: UIVisualEffectView?
|
||||
|
||||
/// 背景层(在iOS13之后window)
|
||||
var backgroundView = UIView()
|
||||
|
||||
/// 设置颜色
|
||||
open var tintColor: UIColor!{
|
||||
didSet {
|
||||
imageView.tintColor = tintColor
|
||||
titleLabel.textColor = tintColor
|
||||
bodyLabel.textColor = tintColor
|
||||
/// 背景层
|
||||
var backgroundView: UIVisualEffectView = {
|
||||
let vev = UIVisualEffectView()
|
||||
if #available(iOS 13.0, *) {
|
||||
vev.effect = UIBlurEffect.init(style: .systemMaterial)
|
||||
} else {
|
||||
vev.effect = UIBlurEffect.init(style: .extraLight)
|
||||
}
|
||||
}
|
||||
vev.layer.masksToBounds = true
|
||||
vev.layer.cornerRadius = toastConfig.cornerRadius
|
||||
return vev
|
||||
}()
|
||||
|
||||
/// 视图模型
|
||||
public var vm = ViewModel()
|
||||
|
@ -118,23 +116,6 @@ public extension ProHUD {
|
|||
}
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func blurMask(_ blurEffectStyle: UIBlurEffect.Style?) -> Toast {
|
||||
if let s = blurEffectStyle {
|
||||
if let bv = blurView {
|
||||
bv.effect = UIBlurEffect.init(style: s)
|
||||
} else {
|
||||
blurView = UIVisualEffectView(effect: UIBlurEffect.init(style: s))
|
||||
blurView?.layer.masksToBounds = true
|
||||
blurView?.layer.cornerRadius = toastConfig.cornerRadius
|
||||
}
|
||||
} else {
|
||||
blurView?.removeFromSuperview()
|
||||
blurView = nil
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func update(title: String?) -> Toast {
|
||||
vm.title = title
|
||||
|
|
|
@ -29,27 +29,27 @@ public extension ProHUD.Toast {
|
|||
/// 错误场景
|
||||
case error
|
||||
|
||||
public var backgroundColor: UIColor {
|
||||
switch self {
|
||||
case .success:
|
||||
return UIColor.green
|
||||
case .warning:
|
||||
return UIColor.yellow
|
||||
case .error:
|
||||
return UIColor.red
|
||||
default:
|
||||
return .clear
|
||||
}
|
||||
}
|
||||
|
||||
public var tintColor: UIColor {
|
||||
switch self {
|
||||
case .success, .error:
|
||||
return .white
|
||||
default:
|
||||
return UIColor.darkGray
|
||||
}
|
||||
}
|
||||
// public var backgroundColor: UIColor {
|
||||
// switch self {
|
||||
// case .success:
|
||||
// return UIColor.green
|
||||
// case .warning:
|
||||
// return UIColor.yellow
|
||||
// case .error:
|
||||
// return UIColor.red
|
||||
// default:
|
||||
// return .clear
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public var tintColor: UIColor {
|
||||
// switch self {
|
||||
// case .success, .error:
|
||||
// return .white
|
||||
// default:
|
||||
// return UIColor.darkGray
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
struct ViewModel {
|
||||
|
|
Loading…
Reference in New Issue