Swift-自定义轻量级HUD
2019-08-10 本文已影响0人
SK丿希望
- 加载
HUDManage.hw_showLoading("加载中...") // 内部封装
- 错误
HUDManage.hw_showError("操作失败")
- 文本
HUDManage.hw_showtitle("点太重了")
- 警告
HWProgressHUD.show(.info, "被警告了", 1) // 原始调用
- 成功
HUDManage.hw_showSuccess("操作成功")
核心代码
open class HWProgressHUD: NSObject {
fileprivate static var windowsTemp = [UIWindow]()
fileprivate static var timer: DispatchSourceTimer?
fileprivate static let instance = HWProgressHUD()
private struct Cache {
static var imageOfCheckmark: UIImage?
static var imageOfCross: UIImage?
static var imageOfInfo: UIImage?
}
// center
fileprivate class func getCenter() -> CGPoint {
return CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2)
}
// delay dismiss
fileprivate class func delayDismiss(_ time: TimeInterval?, completion: HUDCompletedBlock?) {
guard let time = time else { return }
guard time > 0 else { return }
var timeout = time
timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: 0),
queue: DispatchQueue.main)// as! DispatchSource
timer!.schedule(wallDeadline: .now(), repeating: .seconds(1))
timer!.setEventHandler {
if timeout <= 0 {
DispatchQueue.main.async {
dismiss()
completion?()
}
} else {
timeout -= 1
}
}
timer!.resume()
}
// register notification
fileprivate func registerDeviceOrientationNotification() {
NotificationCenter.default.addObserver(HWProgressHUD.instance, selector: #selector(HWProgressHUD.transformWindow(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
}
// remove notification
fileprivate func removeDeviceOrientationNotification() {
NotificationCenter.default.removeObserver(HWProgressHUD.instance)
}
// transform
@objc fileprivate func transformWindow(_ notification: Notification) {
var rotation: CGFloat = 0
switch UIDevice.current.orientation {
case .portrait:
rotation = 0
case .portraitUpsideDown:
rotation = .pi
case .landscapeLeft:
rotation = .pi * 0.5
case .landscapeRight:
rotation = CGFloat(.pi + (.pi * 0.5))
default:
break
}
HWProgressHUD.windowsTemp.forEach {
$0.center = HWProgressHUD.getCenter()
$0.transform = CGAffineTransform(rotationAngle: rotation)
}
}
// draw
// MARK: - 绘画
private class func draw(_ type: HWProgressHUDType) {
let checkmarkShapePath = UIBezierPath()
switch type {
case .success: // draw checkmark
checkmarkShapePath.move(to: CGPoint(x: 5, y: 21))
checkmarkShapePath.addLine(to: CGPoint(x: 16, y: 32))
checkmarkShapePath.addLine(to: CGPoint(x: 35, y:11))
checkmarkShapePath.move(to: CGPoint(x: 5, y: 21))
checkmarkShapePath.close()
case .error: // draw X
checkmarkShapePath.move(to: CGPoint(x: 7, y: 10))
checkmarkShapePath.addLine(to: CGPoint(x: 29, y: 31))
checkmarkShapePath.move(to: CGPoint(x: 7, y: 31))
checkmarkShapePath.addLine(to: CGPoint(x: 29, y: 10))
checkmarkShapePath.move(to: CGPoint(x: 7, y: 10))
checkmarkShapePath.close()
case .info:
checkmarkShapePath.move(to: CGPoint(x: 18, y: 10))
checkmarkShapePath.addLine(to: CGPoint(x: 18, y: 26))
checkmarkShapePath.move(to: CGPoint(x: 18, y: 10))
checkmarkShapePath.close()
UIColor.white.setStroke()
checkmarkShapePath.stroke()
let checkmarkShapePath = UIBezierPath()
checkmarkShapePath.move(to: CGPoint(x: 18, y: 31))
checkmarkShapePath.addArc(withCenter: CGPoint(x: 18, y: 31), radius: 1, startAngle: 0, endAngle: .pi * 2, clockwise: true)
checkmarkShapePath.close()
UIColor.white.setFill()
checkmarkShapePath.fill()
default: break
}
UIColor.white.setStroke()
checkmarkShapePath.stroke()
}
// MARK: - 画勾
fileprivate class var imageOfCheckmark: UIImage {
if (Cache.imageOfCheckmark != nil) {
return Cache.imageOfCheckmark!
}
UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0)
HWProgressHUD.draw(.success)
Cache.imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return Cache.imageOfCheckmark!
}
// MARK: - 画X
fileprivate class var imageOfCross: UIImage {
if (Cache.imageOfCross != nil) {
return Cache.imageOfCross!
}
UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0)
HWProgressHUD.draw(.error)
Cache.imageOfCross = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return Cache.imageOfCross!
}
// MARK: - 画!
fileprivate class var imageOfInfo: UIImage {
if (Cache.imageOfInfo != nil) {
return Cache.imageOfInfo!
}
UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0)
HWProgressHUD.draw(.info)
Cache.imageOfInfo = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return Cache.imageOfInfo!
}
}
public typealias HUDCompletedBlock = () -> Void
public enum HWProgressHUDType {
case loading // 加载
case success // 成功
case error // 失败
case info // 警告
case none // 文字
}
public extension HWProgressHUD {
/// 显示hud
///
/// - Parameters:
/// - type: 类型
/// - text: 内容
/// - time: 消失时间
/// - completion: 消失时回调
public class func show(_ type: HWProgressHUDType,_ text: String,_ time: TimeInterval = 1, completion: HUDCompletedBlock? = nil) {
dismiss()
instance.registerDeviceOrientationNotification()
var isNone: Bool = false
let window = UIWindow()
window.backgroundColor = UIColor.clear
let mainView = UIView()
mainView.layer.cornerRadius = 10
mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.7)
var image = UIImage()
var headView = UIView()
switch type { /// 添加图片
case .success:
image = imageOfCheckmark
case .error:
image = imageOfCross
case .info:
image = imageOfInfo
default:
break
}
switch type { // 添加 headView
case .loading:
headView = UIActivityIndicatorView(style: .whiteLarge)
(headView as! UIActivityIndicatorView).startAnimating()
headView.translatesAutoresizingMaskIntoConstraints = false
mainView.addSubview(headView)
case .success: // 加了fallthrough后,会直接运行【紧跟的后一个】
fallthrough
case .error:
fallthrough
case .info:
headView = UIImageView(image: image)
headView.translatesAutoresizingMaskIntoConstraints = false
mainView.addSubview(headView)
case .none:
isNone = true
}
// label
let label = UILabel()
label.text = text
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: hudlabelSize)
label.textColor = UIColor.white
label.translatesAutoresizingMaskIntoConstraints = false
let arr = NSMutableAttributedString(string: text).hud_addLineSpacing(hudlineSpacing)
label.attributedText = arr
var height: CGFloat = text.count > 0 ? arr.hud_getHeight(hudmaxWidth) : 0 // 因为加了行间距 高度不可能=0 (所有用是否有内容来判断)
height = height+height/label.font.pointSize*hudlineSpacing
var width = arr.hud_getWidth(CGFloat(MAXFLOAT), hudmaxWidth)
if !isNone { // 有图标
width = height > 0 ? width : hudiconWH
height = height > 0 ? height+hudiconWH+hudreserved : hudiconWH
}
label.textAlignment = NSTextAlignment.center
mainView.addSubview(label)
if HWHUDManage.isReceiveEvent == false { // 不接受事件
window.frame = UIScreen.main.bounds
mainView.frame = CGRect(x: (UIScreen.main.bounds.size.width-(width+hudreserved*4))/2, y: (UIScreen.main.bounds.size.height-(height+hudreserved*2))/2, width: width+hudreserved*4, height: height+hudreserved*2)
} else {
let superFrame = CGRect(x: 0, y: 0, width: width+hudreserved*4, height: height+hudreserved*2)
window.frame = superFrame
mainView.frame = superFrame
}
// image
if !isNone { // 有图标
mainView.addConstraint(NSLayoutConstraint(item: headView, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: mainView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: hudreserved))
mainView.addConstraint(NSLayoutConstraint(item: headView, attribute: .centerX, relatedBy: .equal, toItem: mainView, attribute: .centerX, multiplier: 1.0, constant: 0) )
mainView.addConstraint(NSLayoutConstraint(item: headView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: hudiconWH))
mainView.addConstraint(NSLayoutConstraint(item: headView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: hudiconWH))
}
// label
if !isNone { // 如果有图标 + 图标高度 图标和文字间距15
let labelTop = hudreserved + hudiconWH + hudreserved
mainView.addConstraint(NSLayoutConstraint(item: label, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: mainView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: labelTop))
} else { // 没有图标 直接居中
mainView.addConstraint(NSLayoutConstraint(item: label, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.lessThanOrEqual, toItem: mainView, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0))
}
mainView.addConstraint( NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: mainView, attribute: .centerX, multiplier: 1.0, constant: 0) )
mainView.addConstraint( NSLayoutConstraint(item: label, attribute: .width, relatedBy: .lessThanOrEqual, toItem: nil, attribute: .width, multiplier: 1.0, constant: hudmaxWidth))
mainView.addConstraint( NSLayoutConstraint(item: label, attribute: .height, relatedBy: .greaterThanOrEqual, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 0) )
window.windowLevel = UIWindow.Level.alert
window.center = getCenter()
window.isHidden = false
window.addSubview(mainView)
windowsTemp.append(window)
if time != 0 {
delayDismiss(time, completion: completion)
}
}
public class func dismiss() {
timer?.cancel()
timer = nil
instance.removeDeviceOrientationNotification()
if let currentwindow = windowsTemp.last {
for view in currentwindow.subviews {
view.removeFromSuperview()
}
}
windowsTemp.removeAll(keepingCapacity: false)
}
}
单例封装
class HWHUDManage: NSObject {
// MARK: - HUD相关
static let instance: HWHUDManage = HWHUDManage()
/// 是否接收事件 默认接收 如果显示是想屏蔽事件需要把 isReceiveEvent = false
static var isReceiveEvent = true
class var shared: HWHUDManage {
return instance
}
/// 加载HUD
///
/// - Parameter name: 提示语
func hw_showLoading(_ name: String = "正在加载",_ time: TimeInterval? = nil) {
if time == nil {
HWProgressHUD.show(.loading, name, 60)
} else {
HWProgressHUD.show(.loading, name, time ?? 1)
}
}
/// 只显示文字
///
/// - Parameters:
/// - name: 提示语
/// - delay: 延迟时间
func hw_showtitle(_ name: String?,_ delay: TimeInterval = 1) {
HWProgressHUD.show(.none, name ?? "", delay)
}
/// 显示警告
///
/// - Parameters:
/// - name: 提示语
/// - delay: 延迟时间
func hw_showInfo(_ name: String?,_ delay: TimeInterval = 1) {
HWProgressHUD.show(.info, name ?? "", delay)
}
/// 隐藏HUD
func hw_dismiss(){
HWProgressHUD.dismiss()
}
/// 成功提示
func hw_showSuccess(_ name: String) {
HWProgressHUD.show(.success, name, 1)
}
/// 失败提示
func hw_showError(_ name: String) {
HWProgressHUD.show(.error, name, 1)
}
}
extension UIViewController {
/// HUD管理者 使用 HUDManage.hw_showtitleHUD("HUD")
@IBInspectable var HUDManage: HWHUDManage! {
get {
return HWHUDManage.shared
}
set {}
}
}
extension UIView {
/// HUD管理者 使用 HUDManage.hw_showtitleHUD("HUD")
@IBInspectable var HUDManage: HWHUDManage! {
get {
return HWHUDManage.shared
}
set {}
}
}