MBProgress是我非常喜欢用的一个提示组件,GitHub上有更新到Swift2.0版本的(https://github.com/powfulhong/MBProgressHUDForSwift).
奈何作者似乎并没有继续更新的意思,没办法只能手动更新了,直接上代码,希望对小伙伴们有所帮助.
注:我只是针对Swift2.0版本的代码做了升级处理,并没有做任何改动,感谢jdg和powfulhong的无私奉献.
代码地址:https://github.com/Asyncz/MBProgressHUDForSwift3.0
import Foundation
import UIKit
//MARK: - Extension UIView
extension UIView {
func updateUI() {
DispatchQueue.main.async { () -> Void in
self.setNeedsLayout()
self.setNeedsDisplay()
}
}
}
//MARK: - MBProgressHUDDelegate
@objc protocol MBProgressHUDDelegate {
@objc optional func hudWasHidden(_ hud: MBProgressHUD)
}
//MARK: - ENUM
enum MBProgressHUDMode: Int {
case indeterminate = 0
case annularIndeterminate //
case determinate
case determinateHorizontalBar
case annularDeterminate
case customView
case text
}
enum MBProgressHUDAnimation: Int {
case fade = 0
case zoom
case zoomOut
case zoomIn
}
//MARK: - Global var and func
typealias MBProgressHUDCompletionBlock = () -> Void
typealias MBProgressHUDExecutionClosures = () -> Void
let kPadding: CGFloat = 4.0
let kLabelFontSize: CGFloat = 16.0
let kDetailsLabelFontSize: CGFloat = 12.0
func MB_TEXTSIZE(_ text: String?, font: UIFont) -> CGSize {
guard let textTemp = text, textTemp.characters.count > 0 else {
return CGSize.zero
}
return textTemp.size(attributes: [NSFontAttributeName: font])
}
func MB_MULTILINE_TEXTSIZE(_ text: String?, font: UIFont, maxSize: CGSize, mode: NSLineBreakMode) -> CGSize {
guard let textTemp = text, textTemp.characters.count > 0 else {
return CGSize.zero
}
return textTemp.boundingRect(with: maxSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size
}
//MARK: - MBProgressHUD
class MBProgressHUD: UIView {
fileprivate var useAnimation: Bool = true
fileprivate var closureForExecution: MBProgressHUDExecutionClosures?
fileprivate var label: UILabel!
fileprivate var detailsLabel: UILabel!
fileprivate var rotationTransform: CGAffineTransform = CGAffineTransform.identity
fileprivate var indicator: UIView?
fileprivate var graceTimer: Timer?
fileprivate var minShowTimer: Timer?
fileprivate var showStarted: Date?
var customView: UIView? {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var animationType = MBProgressHUDAnimation.fade
var mode = MBProgressHUDMode.indeterminate {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var labelText: String? {
didSet {
label.text = labelText
self.updateUI()
}
}
var detailsLabelText: String? {
didSet {
detailsLabel.text = detailsLabelText
self.updateUI()
}
}
var opacity = 0.8
var color: UIColor?
var labelFont = UIFont.boldSystemFont(ofSize: kLabelFontSize) {
didSet {
label.font = labelFont
self.updateUI()
}
}
var labelColor = UIColor.white {
didSet {
label.textColor = labelColor
self.updateUI()
}
}
var detailsLabelFont = UIFont.boldSystemFont(ofSize: kDetailsLabelFontSize) {
didSet {
detailsLabel.font = detailsLabelFont
self.updateUI()
}
}
var detailsLabelColor = UIColor.white {
didSet {
detailsLabel.textColor = detailsLabelColor
self.updateUI()
}
}
var activityIndicatorColor = UIColor.white {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var xOffset = 0.0
var yOffset = 0.0
var dimBackground = false
var margin = 20.0
var cornerRadius = 10.0
var graceTime = 0.0
var minShowTime = 0.0
var removeFromSuperViewOnHide = false
var minSize: CGSize = CGSize.zero
var square = false
var size: CGSize = CGSize.zero
var taskInprogress = false
var progress: Float = 0.0 {
didSet {
indicator?.setValue(progress, forKey: "progress")
}
}
var completionBlock: MBProgressHUDCompletionBlock?
var delegate: MBProgressHUDDelegate?
// MARK: - Lifecycle
override init(frame: CGRect) {
super.init(frame: frame)
self.contentMode = UIViewContentMode.center
self.autoresizingMask = [UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleBottomMargin, UIViewAutoresizing.flexibleLeftMargin, UIViewAutoresizing.flexibleRightMargin]
self.isOpaque = false
self.backgroundColor = UIColor.clear
self.alpha = 0.0
self.setupLabels()
self.updateIndicators()
}
convenience init(view: UIView?) {
assert(view != nil, "View must not be nil.")
self.init(frame: view!.bounds)
}
convenience init(window: UIWindow) {
self.init(view: window)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.unregisterFromNotifications()
}
// MARK: - Show & Hide
func show(_ animated: Bool) {
assert(Thread.isMainThread, "MBProgressHUD needs to be accessed on the main thread.")
useAnimation = animated
if graceTime > 0.0 {
let newGraceTimer: Timer = Timer(timeInterval: graceTime, target: self, selector: #selector(handleGraceTimer), userInfo: nil, repeats: false)
RunLoop.current.add(newGraceTimer, forMode: RunLoopMode.commonModes)
graceTimer = newGraceTimer
}
// ... otherwise show the HUD imediately
else {
self.showUsingAnimation(useAnimation)
}
}
func hide(_ animated: Bool) {
assert(Thread.isMainThread, "MBProgressHUD needs to be accessed on the main thread.")
useAnimation = animated
// If the minShow time is set, calculate how long the hud was shown,
// and pospone the hiding operation if necessary
if let showStarted = showStarted, minShowTime > 0.0 {
let interv: TimeInterval = Date().timeIntervalSince(showStarted)
guard interv >= minShowTime else {
minShowTimer = Timer(timeInterval: minShowTime - interv, target: self, selector:#selector(handleMinShowTimer) , userInfo: nil, repeats: false)
return
}
}
// if minShowTime > 0.0 && showStarted != nil {
// let interv: NSTimeInterval = NSDate().timeIntervalSinceDate(showStarted!)
// if interv < minShowTime {
// minShowTimer = NSTimer(timeInterval: minShowTime - interv, target: self, selector: "handleMinShowTimer:", userInfo: nil, repeats: false)
// return
// }
// }
// ... otherwise hide the HUD immediately
self.hideUsingAnimation(useAnimation)
}
func hide(_ animated: Bool, afterDelay delay: TimeInterval) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
self.hideDelayed(animated)
}
}
func hideDelayed(_ animated: Bool) {
self.hide(animated)
}
// MARK: - Timer callbacks
func handleGraceTimer(_ theTimer: Timer) {
// Show the HUD only if the task is still running
if taskInprogress {
self.showUsingAnimation(useAnimation)
}
}
@objc fileprivate func handleMinShowTimer(_ theTimer: Timer) {
self.hideUsingAnimation(useAnimation)
}
// MARK: - View Hierrarchy
override func didMoveToSuperview() {
self.updateForCurrentOrientationAnimaged(false)
}
// MARK: - Internal show & hide operations
fileprivate func showUsingAnimation(_ animated: Bool) {
// Cancel any scheduled hideDelayed: calls
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.setNeedsDisplay()
if animated && animationType == .zoomIn {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 0.5, y: 0.5))
} else if animated && animationType == .zoomOut {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 1.5, y: 1.5))
}
self.showStarted = Date()
//Fade in
if animated {
UIView.beginAnimations(nil, context:nil)
UIView.setAnimationDuration(0.30)
self.alpha = 1.0
if animationType == .zoomIn || animationType == .zoomOut {
self.transform = rotationTransform
}
UIView.commitAnimations()
} else {
self.alpha = 1.0
}
}
fileprivate func hideUsingAnimation(_ animated: Bool) {
// Fade out
if animated && showStarted != nil {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.30)
UIView.setAnimationDelegate(self)
UIView.setAnimationDidStop(#selector(animationFinished(_:finished:context:)))
// 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
// in the done method
if animationType == .zoomIn {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 1.5, y: 1.5))
} else if animationType == .zoomOut {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 0.5, y: 0.5))
}
self.alpha = 0.02
UIView.commitAnimations()
} else {
self.alpha = 0.0
self.done()
}
self.showStarted = nil
}
func animationFinished(_ animationID: String?, finished: Bool, context: UnsafeMutableRawPointer) {
self.done()
}
fileprivate func done() {
NSObject.cancelPreviousPerformRequests(withTarget: self)
// isFinished = true
self.alpha = 0.0
if removeFromSuperViewOnHide {
self.removeFromSuperview()
}
if completionBlock != nil {
self.completionBlock!()
self.completionBlock = nil
}
delegate?.hudWasHidden?(self)
}
// MARK: - Threading
func showWhileExecuting(_ closures: @escaping MBProgressHUDExecutionClosures, animated: Bool) {
// Launch execution in new thread
taskInprogress = true
closureForExecution = closures
Thread.detachNewThreadSelector(#selector(launchExecution), toTarget: self, with: nil)
// Show HUD view
self.show(animated)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->()) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(), completionBlock: nil)
//self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default), completionBlock: nil)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), completionBlock completion: MBProgressHUDCompletionBlock?) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(), completionBlock: completion)
//self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default), completionBlock: completion)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), onQueue queue: DispatchQueue) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: queue, completionBlock: nil)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), onQueue queue: DispatchQueue, completionBlock completion: MBProgressHUDCompletionBlock?) {
taskInprogress = true
self.completionBlock = completion
queue.async(execute: { () -> Void in
block()
DispatchQueue.main.async(execute: { () -> Void in
self.cleanUp()
})
})
self.show(animated)
}
func launchExecution() {
autoreleasepool { () -> () in
closureForExecution!()
DispatchQueue.main.async(execute: { () -> Void in
self.cleanUp()
})
}
}
func cleanUp() {
taskInprogress = false
closureForExecution = nil
self.hide(useAnimation)
}
// MARK: - UI
fileprivate func setupLabels() {
label = UILabel(frame: self.bounds)
label.adjustsFontSizeToFitWidth = false
label.textAlignment = NSTextAlignment.center
label.isOpaque = false
label.backgroundColor = UIColor.clear
label.textColor = labelColor
label.font = labelFont
label.text = labelText
self.addSubview(label)
detailsLabel = UILabel(frame: self.bounds)
detailsLabel.font = detailsLabelFont
detailsLabel.adjustsFontSizeToFitWidth = false
detailsLabel.textAlignment = NSTextAlignment.center
detailsLabel.isOpaque = false
detailsLabel.backgroundColor = UIColor.clear
detailsLabel.textColor = detailsLabelColor
detailsLabel.numberOfLines = 0
detailsLabel.font = detailsLabelFont
detailsLabel.text = detailsLabelText
self.addSubview(detailsLabel)
}
fileprivate func updateIndicators() {
let isActivityIndicator: Bool = self.indicator is UIActivityIndicatorView
let isRoundIndicator: Bool = self.indicator is MBRoundProgressView
let isIndeterminatedRoundIndicator: Bool = self.indicator is MBIndeterminatedRoundProgressView
switch self.mode {
case .indeterminate:
let activityIndicator = isActivityIndicator ? (self.indicator as! UIActivityIndicatorView) : UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.whiteLarge)
if !isActivityIndicator {
self.indicator?.removeFromSuperview()
self.indicator = activityIndicator
activityIndicator.startAnimating()
self.addSubview(activityIndicator)
}
activityIndicator.color = activityIndicatorColor
case .annularIndeterminate:
if !isIndeterminatedRoundIndicator {
self.indicator?.removeFromSuperview()
self.indicator = MBIndeterminatedRoundProgressView()
self.addSubview(self.indicator!)
}
case .determinateHorizontalBar:
self.indicator?.removeFromSuperview()
self.indicator = MBBarProgressView()
self.addSubview(self.indicator!)
case .determinate:
fallthrough
case .annularDeterminate:
if !isRoundIndicator {
self.indicator?.removeFromSuperview()
self.indicator = MBRoundProgressView()
self.addSubview(self.indicator!)
}
if self.mode == MBProgressHUDMode.annularDeterminate {
(self.indicator as! MBRoundProgressView).annular = true
}
case .customView where self.customView != self.indicator:
self.indicator?.removeFromSuperview()
self.indicator = self.customView
self.addSubview(self.indicator!)
case .text:
self.indicator?.removeFromSuperview()
self.indicator = nil
default:
break
}
// if mode == MBProgressHUDMode.Indeterminate {
// if !isActivityIndicator {
// indicator?.removeFromSuperview()
// indicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
// (indicator as! UIActivityIndicatorView).startAnimating()
// self.addSubview(indicator!)
// }
// (indicator as! UIActivityIndicatorView).color = activityIndicatorColor
// } else if mode == MBProgressHUDMode.AnnularIndeterminate {
// if !isIndeterminatedRoundIndicator {
// indicator?.removeFromSuperview()
// indicator = MBIndeterminatedRoundProgressView()
// self.addSubview(indicator!)
// }
// } else if mode == MBProgressHUDMode.DeterminateHorizontalBar {
// indicator?.removeFromSuperview()
// indicator = MBBarProgressView()
// self.addSubview(indicator!)
// } else if mode == MBProgressHUDMode.Determinate || mode == MBProgressHUDMode.AnnularDeterminate {
// if !isRoundIndicator {
// indicator?.removeFromSuperview()
// indicator = MBRoundProgressView()
// self.addSubview(indicator!)
// }
// if mode == MBProgressHUDMode.AnnularDeterminate {
// (indicator as! MBRoundProgressView).annular = true
// }
// } else if mode == MBProgressHUDMode.CustomView && customView != indicator {
// indicator?.removeFromSuperview()
// self.indicator = customView
// self.addSubview(indicator!)
// } else if mode == MBProgressHUDMode.Text {
// indicator?.removeFromSuperview()
// indicator = nil
// }
}
// MARK: - Notificaiton
fileprivate func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(statusBarOrientationDidChange), name: NSNotification.Name.UIApplicationDidChangeStatusBarOrientation, object: nil)
}
fileprivate func unregisterFromNotifications() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationDidChangeStatusBarOrientation, object: nil)
}
func statusBarOrientationDidChange(_ notification: Notification) {
if let _ = self.superview {
self.updateForCurrentOrientationAnimaged(true)
}
}
fileprivate func updateForCurrentOrientationAnimaged(_ animated: Bool) {
// Stay in sync with the superview in any case
if let superView = self.superview {
self.bounds = superView.bounds
self.setNeedsDisplay()
}
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
// Entirely cover the parent view
if let parent = self.superview {
self.frame = parent.bounds
}
let bounds: CGRect = self.bounds;
// Determine the total widt and height needed
let maxWidth: CGFloat = bounds.size.width - 4 * CGFloat(margin)
var totalSize: CGSize = CGSize.zero
var indicatorF: CGRect = ((indicator != nil) ? indicator!.bounds : CGRect.zero)
indicatorF.size.width = min(indicatorF.size.width, maxWidth)
totalSize.width = max(totalSize.width, indicatorF.size.width)
totalSize.height += indicatorF.size.height
var labelSize: CGSize = MB_TEXTSIZE(label.text, font: label.font)
labelSize.width = min(labelSize.width, maxWidth)
totalSize.width = max(totalSize.width, labelSize.width)
totalSize.height += labelSize.height
if labelSize.height > 0.0 && indicatorF.size.height > 0.0 {
totalSize.height += kPadding
}
let remainingHeight: CGFloat = bounds.size.height - totalSize.height - kPadding - 4 * CGFloat(margin)
let maxSize: CGSize = CGSize(width: maxWidth, height: remainingHeight)
let detailsLabelSize: CGSize = MB_MULTILINE_TEXTSIZE(detailsLabel.text, font: detailsLabel.font, maxSize: maxSize, mode: detailsLabel.lineBreakMode)
totalSize.width = max(totalSize.width, detailsLabelSize.width)
totalSize.height += detailsLabelSize.height
if detailsLabelSize.height > 0.0 && (indicatorF.size.height > 0.0 || labelSize.height > 0.0) {
totalSize.height += kPadding
}
totalSize.width += 2 * CGFloat(margin)
totalSize.height += 2 * CGFloat(margin)
// Position elements
var yPos: CGFloat = round(((bounds.size.height - totalSize.height) / 2)) + CGFloat(margin) + CGFloat(yOffset)
let xPos: CGFloat = CGFloat(xOffset)
indicatorF.origin.y = yPos
indicatorF.origin.x = round((bounds.size.width - indicatorF.size.width) / 2) + xPos
indicator?.frame = indicatorF
yPos += indicatorF.size.height
if labelSize.height > 0.0 && indicatorF.size.height > 0.0 {
yPos += kPadding
}
var labelF: CGRect = CGRect.zero
labelF.origin.y = yPos
labelF.origin.x = round((bounds.size.width - labelSize.width) / 2) + xPos
labelF.size = labelSize
label.frame = labelF
yPos += labelF.size.height
if detailsLabelSize.height > 0.0 && (indicatorF.size.height > 0.0 || labelSize.height > 0.0) {
yPos += kPadding
}
var detailsLabelF: CGRect = CGRect.zero
detailsLabelF.origin.y = yPos
detailsLabelF.origin.x = round((bounds.size.width - detailsLabelSize.width) / 2) + xPos
detailsLabelF.size = detailsLabelSize
detailsLabel.frame = detailsLabelF
// Enforce minsize and quare rules
if square {
let maxWH: CGFloat = max(totalSize.width, totalSize.height);
if maxWH <= bounds.size.width - 2 * CGFloat(margin) {
totalSize.width = maxWH
}
if maxWH <= bounds.size.height - 2 * CGFloat(margin) {
totalSize.height = maxWH
}
}
if totalSize.width < minSize.width {
totalSize.width = minSize.width
}
if totalSize.height < minSize.height {
totalSize.height = minSize.height
}
size = totalSize
}
// MARK: - BG Drawing
override func draw(_ rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
UIGraphicsPushContext(context)
if self.dimBackground {
//Gradient colours
let gradLocationsNum: size_t = 2
let gradLocations: [CGFloat] = [0.0, 1.0]
let gradColors: [CGFloat] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.75]
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let gradient: CGGradient = CGGradient(colorSpace: colorSpace, colorComponents: gradColors, locations: gradLocations, count: gradLocationsNum)!
//Gradient center
let gradCenter: CGPoint = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
//Gradient radius
let gradRadius: CGFloat = min(self.bounds.size.width , self.bounds.size.height)
//Gradient draw
context.drawRadialGradient(gradient, startCenter: gradCenter, startRadius: 0, endCenter: gradCenter, endRadius: gradRadius,options: CGGradientDrawingOptions.drawsAfterEndLocation)
}
// Set background rect color
if let color = self.color {
context.setFillColor(color.cgColor)
} else {
context.setFillColor(gray: 0.0, alpha: CGFloat(opacity))
}
// Center HUD
let allRect: CGRect = self.bounds
// Draw rounded HUD backgroud rect
let boxRect: CGRect = CGRect(x: round((allRect.size.width - size.width) / 2) + CGFloat(self.xOffset), y: round((allRect.size.height - size.height) / 2) + CGFloat(self.yOffset), width: size.width, height: size.height)
let radius = cornerRadius
context.beginPath()
context.move(to: CGPoint(x: boxRect.minX + CGFloat(radius), y: boxRect.minY))
context.addArc(center: CGPoint(x:boxRect.maxX - CGFloat(radius),y:boxRect.minY + CGFloat(radius)), radius: CGFloat(radius), startAngle: 3 * CGFloat(Double.pi) / 2, endAngle: 0, clockwise: false)
// CGContextAddArc(context, boxRect.maxX - CGFloat(radius), boxRect.minY + CGFloat(radius), CGFloat(radius), 3 * CGFloat(M_PI) / 2, 0, 0)
context.addArc(center: CGPoint(x:boxRect.maxX - CGFloat(radius),y:boxRect.maxY - CGFloat(radius)), radius: CGFloat(radius), startAngle: 0, endAngle: CGFloat(Double.pi) / 2, clockwise: false)
// CGContextAddArc(context, boxRect.maxX - CGFloat(radius), boxRect.maxY - CGFloat(radius), CGFloat(radius), 0, CGFloat(M_PI) / 2, 0)
context.addArc(center: CGPoint(x:boxRect.minX + CGFloat(radius),y:boxRect.maxY - CGFloat(radius)), radius: CGFloat(radius), startAngle: CGFloat(Double.pi) / 2, endAngle: CGFloat(Double.pi), clockwise: false)
// CGContextAddArc(context, boxRect.minX + CGFloat(radius), boxRect.maxY - CGFloat(radius), CGFloat(radius), CGFloat(M_PI) / 2, CGFloat(M_PI), 0)
context.addArc(center: CGPoint(x:boxRect.minX + CGFloat(radius),y:boxRect.minY + CGFloat(radius)), radius: CGFloat(radius), startAngle: CGFloat(Double.pi), endAngle: 3 * CGFloat(Double.pi) / 2, clockwise: false)
// CGContextAddArc(context, boxRect.minX + CGFloat(radius), boxRect.minY + CGFloat(radius), CGFloat(radius), CGFloat(M_PI), 3 * CGFloat(M_PI) / 2, 0)
context.closePath()
context.fillPath()
UIGraphicsPopContext()
}
}
// MARK: - Class methods
extension MBProgressHUD {
class func showHUDAddedTo(_ view: UIView, animated: Bool) -> MBProgressHUD {
let hud: MBProgressHUD = MBProgressHUD(view: view)
hud.removeFromSuperViewOnHide = true
view.addSubview(hud)
hud.show(animated)
return hud
}
class func hideHUDForView(_ view: UIView, animated: Bool) -> Bool {
guard let hud = self.HUDForView(view) else {
return false
}
hud.removeFromSuperViewOnHide = true
hud.hide(animated)
return true
}
class func hideAllHUDsForView(_ view: UIView, animated: Bool) -> Int {
let huds = MBProgressHUD.allHUDsForView(view)
for hud in huds {
hud.removeFromSuperViewOnHide = true
hud.hide(animated)
}
return huds.count
}
class func HUDForView(_ view: UIView) -> MBProgressHUD? {
for subview in Array(view.subviews.reversed()) {
if subview is MBProgressHUD {
return subview as? MBProgressHUD
}
}
return nil
}
class func allHUDsForView(_ view: UIView) -> [MBProgressHUD] {
var huds: [MBProgressHUD] = []
for aView in view.subviews {
if aView is MBProgressHUD {
huds.append(aView as! MBProgressHUD)
}
}
return huds
}
}
// MARK: - MBRoundProgressView
class MBRoundProgressView: UIView {
var progress: Float = 0.0 {
didSet {
self.updateUI()
}
}
var progressTintColor: UIColor {
didSet {
self.updateUI()
}
}
var backgroundTintColor: UIColor {
didSet {
self.updateUI()
}
}
var annular: Bool = false {
didSet {
self.updateUI()
}
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 37.0, height: 37.0))
}
override init(frame: CGRect) {
progressTintColor = UIColor(white: 1.0, alpha: 1.0)
backgroundTintColor = UIColor(white: 1.0, alpha: 0.1)
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let allRect: CGRect = self.bounds
let circleRect: CGRect = allRect.insetBy(dx: 2.0, dy: 2.0)
let context: CGContext = UIGraphicsGetCurrentContext()!
if annular {
// Draw background
let lineWidth: CGFloat = 2.0
let processBackgroundPath: UIBezierPath = UIBezierPath()
processBackgroundPath.lineWidth = lineWidth
processBackgroundPath.lineCapStyle = CGLineCap.butt
let center: CGPoint = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
let radius: CGFloat = (self.bounds.size.width - lineWidth) / 2
let startAngle: CGFloat = -(CGFloat(Double.pi) / 2)
var endAngle: CGFloat = (2 * CGFloat(Double.pi)) + startAngle
processBackgroundPath.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
backgroundTintColor.set()
processBackgroundPath.stroke()
// Draw progress
let processPath: UIBezierPath = UIBezierPath()
processPath.lineCapStyle = CGLineCap.square
processPath.lineWidth = lineWidth
endAngle = CGFloat(progress) * 2 * CGFloat(Double.pi) + startAngle
processPath.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
progressTintColor.set()
processPath.stroke()
} else {
// Draw background
progressTintColor.setStroke()
backgroundTintColor.setFill()
context.setLineWidth(2.0)
context.fillEllipse(in: circleRect)
context.strokeEllipse(in: circleRect)
// Draw progress
let center: CGPoint = CGPoint(x: allRect.size.width / 2, y: allRect.size.height / 2)
let radius: CGFloat = (allRect.size.width - 4) / 2
let startAngle: CGFloat = -(CGFloat(Double.pi) / 2)
let endAngle: CGFloat = CGFloat(progress) * 2 * CGFloat(Double.pi) + startAngle
progressTintColor.setFill()
context.move(to: CGPoint(x: center.x, y: center.y))
context.addArc(center: CGPoint(x:center.x,y:center.y), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
// CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0)
context.closePath()
context.fillPath()
}
}
}
// MARK: - MBBarProgressView
class MBBarProgressView: UIView {
var progress: Float {
didSet {
self.updateUI()
}
}
var lineColor: UIColor {
didSet {
self.updateUI()
}
}
var progressRemainingColor: UIColor {
didSet {
self.updateUI()
}
}
var progressColor: UIColor {
didSet {
self.updateUI()
}
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 120.0, height: 20.0))
}
override init(frame: CGRect) {
progress = 0.0
lineColor = UIColor.white
progressColor = UIColor.white
progressRemainingColor = UIColor.clear
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
context.setLineWidth(2)
context.setStrokeColor(lineColor.cgColor)
context.setFillColor(progressRemainingColor.cgColor)
// Draw background
var radius: CGFloat = (rect.size.height / 2) - 2
context.move(to: CGPoint(x: 2, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:2,y:2), tangent2End: CGPoint(x:radius + 2,y:2), radius: radius)
// CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 2, y: 2))
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:2), tangent2End: CGPoint(x:rect.size.width - 2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius)
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:rect.size.height - 2), tangent2End: CGPoint(x:rect.size.width - radius - 2,y:rect.size.height - 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius)
context.addLine(to: CGPoint(x: radius + 2, y: rect.size.height - 2))
context.addArc(tangent1End: CGPoint(x:2,y:rect.size.height - 2), tangent2End: CGPoint(x:2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height / 2, radius)
context.fillPath()
// Draw border
context.move(to: CGPoint(x: 2, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:2,y:2), tangent2End: CGPoint(x:radius + 2,y:2), radius: radius)
// CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 2, y: 2))
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:2), tangent2End: CGPoint(x:rect.size.width - 2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius)
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:rect.size.height - 2), tangent2End: CGPoint(x:rect.size.width - radius - 2,y:rect.size.height - 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius)
context.addLine(to: CGPoint(x: radius + 2, y: rect.size.height - 2))
context.addArc(tangent1End: CGPoint(x:2,y:rect.size.height - 2), tangent2End: CGPoint(x:2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height / 2, radius)
context.strokePath()
context.setFillColor(progressColor.cgColor)
radius = radius - 2
let amount: CGFloat = CGFloat(progress) * rect.size.width
// Progress in the middle area
if amount >= radius + 4 && amount <= (rect.size.width - radius - 4) {
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: amount, y: 4))
context.addLine(to: CGPoint(x: amount, y: radius + 4))
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: amount, y: rect.size.height - 4))
context.addLine(to: CGPoint(x: amount, y: radius + 4))
context.fillPath()
}
// Progress in the right arc
else if (amount > radius + 4) {
let x: CGFloat = amount - (rect.size.width - radius - 4)
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 4, y: 4))
var angle: CGFloat = -acos(x / radius)
if angle.isNaN{
angle = 0;
}
// if isnan(angle) { angle = 0 }
context.addArc(center: CGPoint(x:rect.size.width - radius - 4,y:rect.size.height / 2), radius: radius, startAngle: CGFloat(Double.pi), endAngle: angle, clockwise: false)
// CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height / 2, radius, CGFloat(M_PI), angle, 0)
context.addLine(to: CGPoint(x: amount, y: rect.size.height / 2))
context.move(to: CGPoint(x: 4, y: rect.size.height/2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 4, y: rect.size.height - 4))
angle = acos(x/radius)
if angle.isNaN {
angle = 0;
}
// if (isnan(angle)) { angle = 0 }
context.addArc(center: CGPoint(x:rect.size.width - radius - 4,y:rect.size.height / 2), radius: radius, startAngle: CGFloat(-Double.pi), endAngle: angle, clockwise: true)
// CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height / 2, radius, CGFloat(-M_PI), angle, 1)
context.addLine(to: CGPoint(x: amount, y: rect.size.height / 2))
context.fillPath()
}
// Progress is in the left arc
else if amount < radius + 4 && amount > 0 {
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: radius + 4, y: rect.size.height / 2))
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: radius + 4, y: rect.size.height / 2))
context.fillPath()
}
}
}
// MARK: - MBIndeterminatedRoundProgressView
class MBIndeterminatedRoundProgressView: UIView {
fileprivate let circleLayer: CAShapeLayer = CAShapeLayer()
var lineColor: UIColor = UIColor.white {
didSet {
self.updateUI()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
setupAndStartRotatingCircle()
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 37.0, height: 37.0))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupAndStartRotatingCircle() {
let circlePath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.bounds.size.width / 2)
circleLayer.frame = self.bounds
circleLayer.path = circlePath.cgPath
circleLayer.strokeColor = lineColor.cgColor
circleLayer.lineWidth = 2.0
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.lineCap = kCALineCapRound
self.layer.addSublayer(circleLayer)
startRotatingCircle()
}
fileprivate func startRotatingCircle() {
let animationForStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animationForStrokeEnd.fromValue = 0.0
animationForStrokeEnd.toValue = 1.0
animationForStrokeEnd.duration = 0.4
animationForStrokeEnd.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
let animationForStrokeStart = CABasicAnimation(keyPath: "strokeStart")
animationForStrokeStart.fromValue = 0.0
animationForStrokeStart.toValue = 1.0
animationForStrokeStart.duration = 0.4
animationForStrokeStart.beginTime = 0.5
animationForStrokeStart.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
let animationGroup = CAAnimationGroup()
animationGroup.animations = [animationForStrokeEnd, animationForStrokeStart]
animationGroup.duration = 0.9
animationGroup.repeatCount = MAXFLOAT
circleLayer.add(animationGroup, forKey: nil)
}
}
简单封装(这个没啥好说的):
import Foundation
import UIKit
extension MBProgressHUD{
class func showText(_ text:String) {
MBProgressHUD.showText(text, toView: nil)
}
class func showText(_ text:String, toView:UIView? ){
if text == "" {
return
}
var view = toView
if view == nil {
view = UIApplication.shared.windows.last
}
var hud = MBProgressHUD.HUDForView(view!)
if hud == nil {
hud = MBProgressHUD.showHUDAddedTo(view!, animated: true)
}
// let hud: MBProgressHUD = MBProgressHUD.showHUDAddedTo(view!, animated: true)
// Configure for text only and offset down
hud!.mode = .text
hud!.labelText = text
// hud.margin = 10.0 //默认20 改为10会变窄
hud!.removeFromSuperViewOnHide = true
hud!.hide(true, afterDelay: 1)
}
class func showWait(_ message:String?)->MBProgressHUD{
let view = UIApplication.shared.windows.last
let hud: MBProgressHUD = MBProgressHUD.showHUDAddedTo(view!, animated: true)
hud.labelText = message
hud.removeFromSuperViewOnHide = true
hud.show(true)
return hud
}
class func showWait()->MBProgressHUD{
return MBProgressHUD.showWait(nil)
}
class func hideHUDForView(_ forView:UIView?){
var view = forView
if view == nil {
view = UIApplication.shared.windows.last
}
_ = self.hideHUDForView(view!, animated: true)
}
class func hideHUD(){
MBProgressHUD.hideHUDForView(nil)
}
}
代码没上传,自用
import Foundation
import UIKit
//MARK: - Extension UIView
extension UIView {
func updateUI() {
DispatchQueue.main.async { () -> Void in
self.setNeedsLayout()
self.setNeedsDisplay()
}
}
}
//MARK: - MBProgressHUDDelegate
@objc protocol MBProgressHUDDelegate {
@objc optional func hudWasHidden(_ hud: MBProgressHUD)
}
//MARK: - ENUM
enum MBProgressHUDMode: Int {
case indeterminate = 0
case annularIndeterminate //
case determinate
case determinateHorizontalBar
case annularDeterminate
case customView
case text
}
enum MBProgressHUDAnimation: Int {
case fade = 0
case zoom
case zoomOut
case zoomIn
}
//MARK: - Global var and func
typealias MBProgressHUDCompletionBlock = () -> Void
typealias MBProgressHUDExecutionClosures = () -> Void
let kPadding: CGFloat = 4.0
let kLabelFontSize: CGFloat = 16.0
let kDetailsLabelFontSize: CGFloat = 12.0
func MB_TEXTSIZE(_ text: String?, font: UIFont) -> CGSize {
guard let textTemp = text, textTemp.count > 0 else {
return CGSize.zero
}
return textTemp.size(withAttributes: [NSAttributedStringKey.font: font])
}
func MB_MULTILINE_TEXTSIZE(_ text: String?, font: UIFont, maxSize: CGSize, mode: NSLineBreakMode) -> CGSize {
guard let textTemp = text, textTemp.count > 0 else {
return CGSize.zero
}
return textTemp.boundingRect(with: maxSize, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil).size
}
//MARK: - MBProgressHUD
class MBProgressHUD: UIView {
fileprivate var useAnimation: Bool = true
fileprivate var closureForExecution: MBProgressHUDExecutionClosures?
fileprivate var label: UILabel!
fileprivate var detailsLabel: UILabel!
fileprivate var rotationTransform: CGAffineTransform = CGAffineTransform.identity
fileprivate var indicator: UIView?
fileprivate var graceTimer: Timer?
fileprivate var minShowTimer: Timer?
fileprivate var showStarted: Date?
var customView: UIView? {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var animationType = MBProgressHUDAnimation.fade
var mode = MBProgressHUDMode.indeterminate {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var labelText: String? {
didSet {
label.text = labelText
self.updateUI()
}
}
var detailsLabelText: String? {
didSet {
detailsLabel.text = detailsLabelText
self.updateUI()
}
}
var opacity = 0.8
var color: UIColor?
var labelFont = UIFont.boldSystemFont(ofSize: kLabelFontSize) {
didSet {
label.font = labelFont
self.updateUI()
}
}
var labelColor = UIColor.white {
didSet {
label.textColor = labelColor
self.updateUI()
}
}
var detailsLabelFont = UIFont.boldSystemFont(ofSize: kDetailsLabelFontSize) {
didSet {
detailsLabel.font = detailsLabelFont
self.updateUI()
}
}
var detailsLabelColor = UIColor.white {
didSet {
detailsLabel.textColor = detailsLabelColor
self.updateUI()
}
}
var activityIndicatorColor = UIColor.white {
didSet {
self.updateIndicators()
self.updateUI()
}
}
var xOffset = 0.0
var yOffset = 0.0
var dimBackground = false
var margin = 20.0
var cornerRadius = 10.0
var graceTime = 0.0
var minShowTime = 0.0
var removeFromSuperViewOnHide = false
var minSize: CGSize = CGSize.zero
var square = false
var size: CGSize = CGSize.zero
var taskInprogress = false
var progress: Float = 0.0 {
didSet {
indicator?.setValue(progress, forKey: "progress")
}
}
var completionBlock: MBProgressHUDCompletionBlock?
var delegate: MBProgressHUDDelegate?
// MARK: - Lifecycle
override init(frame: CGRect) {
super.init(frame: frame)
self.contentMode = UIViewContentMode.center
self.autoresizingMask = [UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleBottomMargin, UIViewAutoresizing.flexibleLeftMargin, UIViewAutoresizing.flexibleRightMargin]
self.isOpaque = false
self.backgroundColor = UIColor.clear
self.alpha = 0.0
self.setupLabels()
self.updateIndicators()
}
convenience init(view: UIView?) {
assert(view != nil, "View must not be nil.")
self.init(frame: view!.bounds)
}
convenience init(window: UIWindow) {
self.init(view: window)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.unregisterFromNotifications()
}
// MARK: - Show & Hide
func show(_ animated: Bool) {
assert(Thread.isMainThread, "MBProgressHUD needs to be accessed on the main thread.")
useAnimation = animated
if graceTime > 0.0 {
let newGraceTimer: Timer = Timer(timeInterval: graceTime, target: self, selector: #selector(handleGraceTimer), userInfo: nil, repeats: false)
RunLoop.current.add(newGraceTimer, forMode: RunLoopMode.commonModes)
graceTimer = newGraceTimer
}
// ... otherwise show the HUD imediately
else {
self.showUsingAnimation(useAnimation)
}
}
func hide(_ animated: Bool) {
assert(Thread.isMainThread, "MBProgressHUD needs to be accessed on the main thread.")
useAnimation = animated
// If the minShow time is set, calculate how long the hud was shown,
// and pospone the hiding operation if necessary
if let showStarted = showStarted, minShowTime > 0.0 {
let interv: TimeInterval = Date().timeIntervalSince(showStarted)
guard interv >= minShowTime else {
minShowTimer = Timer(timeInterval: minShowTime - interv, target: self, selector:#selector(handleMinShowTimer) , userInfo: nil, repeats: false)
return
}
}
// if minShowTime > 0.0 && showStarted != nil {
// let interv: NSTimeInterval = NSDate().timeIntervalSinceDate(showStarted!)
// if interv < minShowTime {
// minShowTimer = NSTimer(timeInterval: minShowTime - interv, target: self, selector: "handleMinShowTimer:", userInfo: nil, repeats: false)
// return
// }
// }
// ... otherwise hide the HUD immediately
self.hideUsingAnimation(useAnimation)
}
func hide(_ animated: Bool, afterDelay delay: TimeInterval) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
self.hideDelayed(animated)
}
}
func hideDelayed(_ animated: Bool) {
self.hide(animated)
}
// MARK: - Timer callbacks
@objc func handleGraceTimer(_ theTimer: Timer) {
// Show the HUD only if the task is still running
if taskInprogress {
self.showUsingAnimation(useAnimation)
}
}
@objc fileprivate func handleMinShowTimer(_ theTimer: Timer) {
self.hideUsingAnimation(useAnimation)
}
// MARK: - View Hierrarchy
override func didMoveToSuperview() {
self.updateForCurrentOrientationAnimaged(false)
}
// MARK: - Internal show & hide operations
fileprivate func showUsingAnimation(_ animated: Bool) {
// Cancel any scheduled hideDelayed: calls
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.setNeedsDisplay()
if animated && animationType == .zoomIn {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 0.5, y: 0.5))
} else if animated && animationType == .zoomOut {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 1.5, y: 1.5))
}
self.showStarted = Date()
//Fade in
if animated {
UIView.beginAnimations(nil, context:nil)
UIView.setAnimationDuration(0.30)
self.alpha = 1.0
if animationType == .zoomIn || animationType == .zoomOut {
self.transform = rotationTransform
}
UIView.commitAnimations()
} else {
self.alpha = 1.0
}
}
fileprivate func hideUsingAnimation(_ animated: Bool) {
// Fade out
if animated && showStarted != nil {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.30)
UIView.setAnimationDelegate(self)
UIView.setAnimationDidStop(#selector(animationFinished(_:finished:context:)))
// 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
// in the done method
if animationType == .zoomIn {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 1.5, y: 1.5))
} else if animationType == .zoomOut {
self.transform = rotationTransform.concatenating(CGAffineTransform(scaleX: 0.5, y: 0.5))
}
self.alpha = 0.02
UIView.commitAnimations()
} else {
self.alpha = 0.0
self.done()
}
self.showStarted = nil
}
@objc func animationFinished(_ animationID: String?, finished: Bool, context: UnsafeMutableRawPointer) {
self.done()
}
fileprivate func done() {
NSObject.cancelPreviousPerformRequests(withTarget: self)
// isFinished = true
self.alpha = 0.0
if removeFromSuperViewOnHide {
self.removeFromSuperview()
}
if completionBlock != nil {
self.completionBlock!()
self.completionBlock = nil
}
delegate?.hudWasHidden?(self)
}
// MARK: - Threading
func showWhileExecuting(_ closures: @escaping MBProgressHUDExecutionClosures, animated: Bool) {
// Launch execution in new thread
taskInprogress = true
closureForExecution = closures
Thread.detachNewThreadSelector(#selector(launchExecution), toTarget: self, with: nil)
// Show HUD view
self.show(animated)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->()) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(), completionBlock: nil)
//self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default), completionBlock: nil)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), completionBlock completion: MBProgressHUDCompletionBlock?) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(), completionBlock: completion)
//self.showAnimated(animated, whileExecutingBlock: block, onQueue: DispatchQueue.global(priority: DispatchQueue.GlobalQueuePriority.default), completionBlock: completion)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), onQueue queue: DispatchQueue) {
self.showAnimated(animated, whileExecutingBlock: block, onQueue: queue, completionBlock: nil)
}
func showAnimated(_ animated: Bool, whileExecutingBlock block: @escaping ()->(), onQueue queue: DispatchQueue, completionBlock completion: MBProgressHUDCompletionBlock?) {
taskInprogress = true
self.completionBlock = completion
queue.async(execute: { () -> Void in
block()
DispatchQueue.main.async(execute: { () -> Void in
self.cleanUp()
})
})
self.show(animated)
}
@objc func launchExecution() {
autoreleasepool { () -> () in
closureForExecution!()
DispatchQueue.main.async(execute: { () -> Void in
self.cleanUp()
})
}
}
func cleanUp() {
taskInprogress = false
closureForExecution = nil
self.hide(useAnimation)
}
// MARK: - UI
fileprivate func setupLabels() {
label = UILabel(frame: self.bounds)
label.adjustsFontSizeToFitWidth = false
label.textAlignment = NSTextAlignment.center
label.isOpaque = false
label.backgroundColor = UIColor.clear
label.textColor = labelColor
label.font = labelFont
label.text = labelText
self.addSubview(label)
detailsLabel = UILabel(frame: self.bounds)
detailsLabel.font = detailsLabelFont
detailsLabel.adjustsFontSizeToFitWidth = false
detailsLabel.textAlignment = NSTextAlignment.center
detailsLabel.isOpaque = false
detailsLabel.backgroundColor = UIColor.clear
detailsLabel.textColor = detailsLabelColor
detailsLabel.numberOfLines = 0
detailsLabel.font = detailsLabelFont
detailsLabel.text = detailsLabelText
self.addSubview(detailsLabel)
}
fileprivate func updateIndicators() {
let isActivityIndicator: Bool = self.indicator is UIActivityIndicatorView
let isRoundIndicator: Bool = self.indicator is MBRoundProgressView
let isIndeterminatedRoundIndicator: Bool = self.indicator is MBIndeterminatedRoundProgressView
switch self.mode {
case .indeterminate:
let activityIndicator = isActivityIndicator ? (self.indicator as! UIActivityIndicatorView) : UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.whiteLarge)
if !isActivityIndicator {
self.indicator?.removeFromSuperview()
self.indicator = activityIndicator
activityIndicator.startAnimating()
self.addSubview(activityIndicator)
}
activityIndicator.color = activityIndicatorColor
case .annularIndeterminate:
if !isIndeterminatedRoundIndicator {
self.indicator?.removeFromSuperview()
self.indicator = MBIndeterminatedRoundProgressView()
self.addSubview(self.indicator!)
}
case .determinateHorizontalBar:
self.indicator?.removeFromSuperview()
self.indicator = MBBarProgressView()
self.addSubview(self.indicator!)
case .determinate:
fallthrough
case .annularDeterminate:
if !isRoundIndicator {
self.indicator?.removeFromSuperview()
self.indicator = MBRoundProgressView()
self.addSubview(self.indicator!)
}
if self.mode == MBProgressHUDMode.annularDeterminate {
(self.indicator as! MBRoundProgressView).annular = true
}
case .customView where self.customView != self.indicator:
self.indicator?.removeFromSuperview()
self.indicator = self.customView
self.addSubview(self.indicator!)
case .text:
self.indicator?.removeFromSuperview()
self.indicator = nil
default:
break
}
// if mode == MBProgressHUDMode.Indeterminate {
// if !isActivityIndicator {
// indicator?.removeFromSuperview()
// indicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
// (indicator as! UIActivityIndicatorView).startAnimating()
// self.addSubview(indicator!)
// }
// (indicator as! UIActivityIndicatorView).color = activityIndicatorColor
// } else if mode == MBProgressHUDMode.AnnularIndeterminate {
// if !isIndeterminatedRoundIndicator {
// indicator?.removeFromSuperview()
// indicator = MBIndeterminatedRoundProgressView()
// self.addSubview(indicator!)
// }
// } else if mode == MBProgressHUDMode.DeterminateHorizontalBar {
// indicator?.removeFromSuperview()
// indicator = MBBarProgressView()
// self.addSubview(indicator!)
// } else if mode == MBProgressHUDMode.Determinate || mode == MBProgressHUDMode.AnnularDeterminate {
// if !isRoundIndicator {
// indicator?.removeFromSuperview()
// indicator = MBRoundProgressView()
// self.addSubview(indicator!)
// }
// if mode == MBProgressHUDMode.AnnularDeterminate {
// (indicator as! MBRoundProgressView).annular = true
// }
// } else if mode == MBProgressHUDMode.CustomView && customView != indicator {
// indicator?.removeFromSuperview()
// self.indicator = customView
// self.addSubview(indicator!)
// } else if mode == MBProgressHUDMode.Text {
// indicator?.removeFromSuperview()
// indicator = nil
// }
}
// MARK: - Notificaiton
fileprivate func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(statusBarOrientationDidChange), name: NSNotification.Name.UIApplicationDidChangeStatusBarOrientation, object: nil)
}
fileprivate func unregisterFromNotifications() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationDidChangeStatusBarOrientation, object: nil)
}
@objc func statusBarOrientationDidChange(_ notification: Notification) {
if let _ = self.superview {
self.updateForCurrentOrientationAnimaged(true)
}
}
fileprivate func updateForCurrentOrientationAnimaged(_ animated: Bool) {
// Stay in sync with the superview in any case
if let superView = self.superview {
self.bounds = superView.bounds
self.setNeedsDisplay()
}
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
// Entirely cover the parent view
if let parent = self.superview {
self.frame = parent.bounds
}
let bounds: CGRect = self.bounds;
// Determine the total widt and height needed
let maxWidth: CGFloat = bounds.size.width - 4 * CGFloat(margin)
var totalSize: CGSize = CGSize.zero
var indicatorF: CGRect = ((indicator != nil) ? indicator!.bounds : CGRect.zero)
indicatorF.size.width = min(indicatorF.size.width, maxWidth)
totalSize.width = max(totalSize.width, indicatorF.size.width)
totalSize.height += indicatorF.size.height
var labelSize: CGSize = MB_TEXTSIZE(label.text, font: label.font)
labelSize.width = min(labelSize.width, maxWidth)
totalSize.width = max(totalSize.width, labelSize.width)
totalSize.height += labelSize.height
if labelSize.height > 0.0 && indicatorF.size.height > 0.0 {
totalSize.height += kPadding
}
let remainingHeight: CGFloat = bounds.size.height - totalSize.height - kPadding - 4 * CGFloat(margin)
let maxSize: CGSize = CGSize(width: maxWidth, height: remainingHeight)
let detailsLabelSize: CGSize = MB_MULTILINE_TEXTSIZE(detailsLabel.text, font: detailsLabel.font, maxSize: maxSize, mode: detailsLabel.lineBreakMode)
totalSize.width = max(totalSize.width, detailsLabelSize.width)
totalSize.height += detailsLabelSize.height
if detailsLabelSize.height > 0.0 && (indicatorF.size.height > 0.0 || labelSize.height > 0.0) {
totalSize.height += kPadding
}
totalSize.width += 2 * CGFloat(margin)
totalSize.height += 2 * CGFloat(margin)
// Position elements
var yPos: CGFloat = round(((bounds.size.height - totalSize.height) / 2)) + CGFloat(margin) + CGFloat(yOffset)
let xPos: CGFloat = CGFloat(xOffset)
indicatorF.origin.y = yPos
indicatorF.origin.x = round((bounds.size.width - indicatorF.size.width) / 2) + xPos
indicator?.frame = indicatorF
yPos += indicatorF.size.height
if labelSize.height > 0.0 && indicatorF.size.height > 0.0 {
yPos += kPadding
}
var labelF: CGRect = CGRect.zero
labelF.origin.y = yPos
labelF.origin.x = round((bounds.size.width - labelSize.width) / 2) + xPos
labelF.size = labelSize
label.frame = labelF
yPos += labelF.size.height
if detailsLabelSize.height > 0.0 && (indicatorF.size.height > 0.0 || labelSize.height > 0.0) {
yPos += kPadding
}
var detailsLabelF: CGRect = CGRect.zero
detailsLabelF.origin.y = yPos
detailsLabelF.origin.x = round((bounds.size.width - detailsLabelSize.width) / 2) + xPos
detailsLabelF.size = detailsLabelSize
detailsLabel.frame = detailsLabelF
// Enforce minsize and quare rules
if square {
let maxWH: CGFloat = max(totalSize.width, totalSize.height);
if maxWH <= bounds.size.width - 2 * CGFloat(margin) {
totalSize.width = maxWH
}
if maxWH <= bounds.size.height - 2 * CGFloat(margin) {
totalSize.height = maxWH
}
}
if totalSize.width < minSize.width {
totalSize.width = minSize.width
}
if totalSize.height < minSize.height {
totalSize.height = minSize.height
}
size = totalSize
}
// MARK: - BG Drawing
override func draw(_ rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
UIGraphicsPushContext(context)
if self.dimBackground {
//Gradient colours
let gradLocationsNum: size_t = 2
let gradLocations: [CGFloat] = [0.0, 1.0]
let gradColors: [CGFloat] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.75]
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let gradient: CGGradient = CGGradient(colorSpace: colorSpace, colorComponents: gradColors, locations: gradLocations, count: gradLocationsNum)!
//Gradient center
let gradCenter: CGPoint = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
//Gradient radius
let gradRadius: CGFloat = min(self.bounds.size.width , self.bounds.size.height)
//Gradient draw
context.drawRadialGradient(gradient, startCenter: gradCenter, startRadius: 0, endCenter: gradCenter, endRadius: gradRadius,options: CGGradientDrawingOptions.drawsAfterEndLocation)
}
// Set background rect color
if let color = self.color {
context.setFillColor(color.cgColor)
} else {
context.setFillColor(gray: 0.0, alpha: CGFloat(opacity))
}
// Center HUD
let allRect: CGRect = self.bounds
// Draw rounded HUD backgroud rect
let boxRect: CGRect = CGRect(x: round((allRect.size.width - size.width) / 2) + CGFloat(self.xOffset), y: round((allRect.size.height - size.height) / 2) + CGFloat(self.yOffset), width: size.width, height: size.height)
let radius = cornerRadius
context.beginPath()
context.move(to: CGPoint(x: boxRect.minX + CGFloat(radius), y: boxRect.minY))
context.addArc(center: CGPoint(x:boxRect.maxX - CGFloat(radius),y:boxRect.minY + CGFloat(radius)), radius: CGFloat(radius), startAngle: 3 * CGFloat(Double.pi) / 2, endAngle: 0, clockwise: false)
// CGContextAddArc(context, boxRect.maxX - CGFloat(radius), boxRect.minY + CGFloat(radius), CGFloat(radius), 3 * CGFloat(M_PI) / 2, 0, 0)
context.addArc(center: CGPoint(x:boxRect.maxX - CGFloat(radius),y:boxRect.maxY - CGFloat(radius)), radius: CGFloat(radius), startAngle: 0, endAngle: CGFloat(Double.pi) / 2, clockwise: false)
// CGContextAddArc(context, boxRect.maxX - CGFloat(radius), boxRect.maxY - CGFloat(radius), CGFloat(radius), 0, CGFloat(M_PI) / 2, 0)
context.addArc(center: CGPoint(x:boxRect.minX + CGFloat(radius),y:boxRect.maxY - CGFloat(radius)), radius: CGFloat(radius), startAngle: CGFloat(Double.pi) / 2, endAngle: CGFloat(Double.pi), clockwise: false)
// CGContextAddArc(context, boxRect.minX + CGFloat(radius), boxRect.maxY - CGFloat(radius), CGFloat(radius), CGFloat(M_PI) / 2, CGFloat(M_PI), 0)
context.addArc(center: CGPoint(x:boxRect.minX + CGFloat(radius),y:boxRect.minY + CGFloat(radius)), radius: CGFloat(radius), startAngle: CGFloat(Double.pi), endAngle: 3 * CGFloat(Double.pi) / 2, clockwise: false)
// CGContextAddArc(context, boxRect.minX + CGFloat(radius), boxRect.minY + CGFloat(radius), CGFloat(radius), CGFloat(M_PI), 3 * CGFloat(M_PI) / 2, 0)
context.closePath()
context.fillPath()
UIGraphicsPopContext()
}
}
// MARK: - Class methods
extension MBProgressHUD {
class func showHUDAddedTo(_ view: UIView, animated: Bool) -> MBProgressHUD {
let hud: MBProgressHUD = MBProgressHUD(view: view)
hud.removeFromSuperViewOnHide = true
view.addSubview(hud)
hud.show(animated)
return hud
}
class func hideHUDForView(_ view: UIView, animated: Bool) -> Bool {
guard let hud = self.HUDForView(view) else {
return false
}
hud.removeFromSuperViewOnHide = true
hud.hide(animated)
return true
}
class func hideAllHUDsForView(_ view: UIView, animated: Bool) -> Int {
let huds = MBProgressHUD.allHUDsForView(view)
for hud in huds {
hud.removeFromSuperViewOnHide = true
hud.hide(animated)
}
return huds.count
}
class func HUDForView(_ view: UIView) -> MBProgressHUD? {
for subview in Array(view.subviews.reversed()) {
if subview is MBProgressHUD {
return subview as? MBProgressHUD
}
}
return nil
}
class func allHUDsForView(_ view: UIView) -> [MBProgressHUD] {
var huds: [MBProgressHUD] = []
for aView in view.subviews {
if aView is MBProgressHUD {
huds.append(aView as! MBProgressHUD)
}
}
return huds
}
}
// MARK: - MBRoundProgressView
class MBRoundProgressView: UIView {
var progress: Float = 0.0 {
didSet {
self.updateUI()
}
}
var progressTintColor: UIColor {
didSet {
self.updateUI()
}
}
var backgroundTintColor: UIColor {
didSet {
self.updateUI()
}
}
var annular: Bool = false {
didSet {
self.updateUI()
}
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 37.0, height: 37.0))
}
override init(frame: CGRect) {
progressTintColor = UIColor(white: 1.0, alpha: 1.0)
backgroundTintColor = UIColor(white: 1.0, alpha: 0.1)
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let allRect: CGRect = self.bounds
let circleRect: CGRect = allRect.insetBy(dx: 2.0, dy: 2.0)
let context: CGContext = UIGraphicsGetCurrentContext()!
if annular {
// Draw background
let lineWidth: CGFloat = 2.0
let processBackgroundPath: UIBezierPath = UIBezierPath()
processBackgroundPath.lineWidth = lineWidth
processBackgroundPath.lineCapStyle = CGLineCap.butt
let center: CGPoint = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
let radius: CGFloat = (self.bounds.size.width - lineWidth) / 2
let startAngle: CGFloat = -(CGFloat(Double.pi) / 2)
var endAngle: CGFloat = (2 * CGFloat(Double.pi)) + startAngle
processBackgroundPath.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
backgroundTintColor.set()
processBackgroundPath.stroke()
// Draw progress
let processPath: UIBezierPath = UIBezierPath()
processPath.lineCapStyle = CGLineCap.square
processPath.lineWidth = lineWidth
endAngle = CGFloat(progress) * 2 * CGFloat(Double.pi) + startAngle
processPath.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
progressTintColor.set()
processPath.stroke()
} else {
// Draw background
progressTintColor.setStroke()
backgroundTintColor.setFill()
context.setLineWidth(2.0)
context.fillEllipse(in: circleRect)
context.strokeEllipse(in: circleRect)
// Draw progress
let center: CGPoint = CGPoint(x: allRect.size.width / 2, y: allRect.size.height / 2)
let radius: CGFloat = (allRect.size.width - 4) / 2
let startAngle: CGFloat = -(CGFloat(Double.pi) / 2)
let endAngle: CGFloat = CGFloat(progress) * 2 * CGFloat(Double.pi) + startAngle
progressTintColor.setFill()
context.move(to: CGPoint(x: center.x, y: center.y))
context.addArc(center: CGPoint(x:center.x,y:center.y), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
// CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0)
context.closePath()
context.fillPath()
}
}
}
// MARK: - MBBarProgressView
class MBBarProgressView: UIView {
var progress: Float {
didSet {
self.updateUI()
}
}
var lineColor: UIColor {
didSet {
self.updateUI()
}
}
var progressRemainingColor: UIColor {
didSet {
self.updateUI()
}
}
var progressColor: UIColor {
didSet {
self.updateUI()
}
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 120.0, height: 20.0))
}
override init(frame: CGRect) {
progress = 0.0
lineColor = UIColor.white
progressColor = UIColor.white
progressRemainingColor = UIColor.clear
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
let context: CGContext = UIGraphicsGetCurrentContext()!
context.setLineWidth(2)
context.setStrokeColor(lineColor.cgColor)
context.setFillColor(progressRemainingColor.cgColor)
// Draw background
var radius: CGFloat = (rect.size.height / 2) - 2
context.move(to: CGPoint(x: 2, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:2,y:2), tangent2End: CGPoint(x:radius + 2,y:2), radius: radius)
// CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 2, y: 2))
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:2), tangent2End: CGPoint(x:rect.size.width - 2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius)
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:rect.size.height - 2), tangent2End: CGPoint(x:rect.size.width - radius - 2,y:rect.size.height - 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius)
context.addLine(to: CGPoint(x: radius + 2, y: rect.size.height - 2))
context.addArc(tangent1End: CGPoint(x:2,y:rect.size.height - 2), tangent2End: CGPoint(x:2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height / 2, radius)
context.fillPath()
// Draw border
context.move(to: CGPoint(x: 2, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:2,y:2), tangent2End: CGPoint(x:radius + 2,y:2), radius: radius)
// CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 2, y: 2))
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:2), tangent2End: CGPoint(x:rect.size.width - 2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius)
context.addArc(tangent1End: CGPoint(x:rect.size.width - 2,y:rect.size.height - 2), tangent2End: CGPoint(x:rect.size.width - radius - 2,y:rect.size.height - 2), radius: radius)
// CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius)
context.addLine(to: CGPoint(x: radius + 2, y: rect.size.height - 2))
context.addArc(tangent1End: CGPoint(x:2,y:rect.size.height - 2), tangent2End: CGPoint(x:2,y:rect.size.height / 2), radius: radius)
// CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height / 2, radius)
context.strokePath()
context.setFillColor(progressColor.cgColor)
radius = radius - 2
let amount: CGFloat = CGFloat(progress) * rect.size.width
// Progress in the middle area
if amount >= radius + 4 && amount <= (rect.size.width - radius - 4) {
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: amount, y: 4))
context.addLine(to: CGPoint(x: amount, y: radius + 4))
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: amount, y: rect.size.height - 4))
context.addLine(to: CGPoint(x: amount, y: radius + 4))
context.fillPath()
}
// Progress in the right arc
else if (amount > radius + 4) {
let x: CGFloat = amount - (rect.size.width - radius - 4)
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 4, y: 4))
var angle: CGFloat = -acos(x / radius)
if angle.isNaN{
angle = 0;
}
// if isnan(angle) { angle = 0 }
context.addArc(center: CGPoint(x:rect.size.width - radius - 4,y:rect.size.height / 2), radius: radius, startAngle: CGFloat(Double.pi), endAngle: angle, clockwise: false)
// CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height / 2, radius, CGFloat(M_PI), angle, 0)
context.addLine(to: CGPoint(x: amount, y: rect.size.height / 2))
context.move(to: CGPoint(x: 4, y: rect.size.height/2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: rect.size.width - radius - 4, y: rect.size.height - 4))
angle = acos(x/radius)
if angle.isNaN {
angle = 0;
}
// if (isnan(angle)) { angle = 0 }
context.addArc(center: CGPoint(x:rect.size.width - radius - 4,y:rect.size.height / 2), radius: radius, startAngle: CGFloat(-Double.pi), endAngle: angle, clockwise: true)
// CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height / 2, radius, CGFloat(-M_PI), angle, 1)
context.addLine(to: CGPoint(x: amount, y: rect.size.height / 2))
context.fillPath()
}
// Progress is in the left arc
else if amount < radius + 4 && amount > 0 {
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:4), tangent2End: CGPoint(x:radius + 4,y:4), radius: radius)
// CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius)
context.addLine(to: CGPoint(x: radius + 4, y: rect.size.height / 2))
context.move(to: CGPoint(x: 4, y: rect.size.height / 2))
context.addArc(tangent1End: CGPoint(x:4,y:rect.size.height - 4), tangent2End: CGPoint(x:radius + 4,y:rect.size.height - 4), radius: radius)
// CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius)
context.addLine(to: CGPoint(x: radius + 4, y: rect.size.height / 2))
context.fillPath()
}
}
}
// MARK: - MBIndeterminatedRoundProgressView
class MBIndeterminatedRoundProgressView: UIView {
fileprivate let circleLayer: CAShapeLayer = CAShapeLayer()
var lineColor: UIColor = UIColor.white {
didSet {
self.updateUI()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self.isOpaque = false
setupAndStartRotatingCircle()
}
convenience init() {
self.init(frame: CGRect(x: 0.0, y: 0.0, width: 37.0, height: 37.0))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupAndStartRotatingCircle() {
let circlePath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.bounds.size.width / 2)
circleLayer.frame = self.bounds
circleLayer.path = circlePath.cgPath
circleLayer.strokeColor = lineColor.cgColor
circleLayer.lineWidth = 2.0
circleLayer.fillColor = UIColor.clear.cgColor
circleLayer.lineCap = kCALineCapRound
self.layer.addSublayer(circleLayer)
startRotatingCircle()
}
fileprivate func startRotatingCircle() {
let animationForStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animationForStrokeEnd.fromValue = 0.0
animationForStrokeEnd.toValue = 1.0
animationForStrokeEnd.duration = 0.4
animationForStrokeEnd.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
let animationForStrokeStart = CABasicAnimation(keyPath: "strokeStart")
animationForStrokeStart.fromValue = 0.0
animationForStrokeStart.toValue = 1.0
animationForStrokeStart.duration = 0.4
animationForStrokeStart.beginTime = 0.5
animationForStrokeStart.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
let animationGroup = CAAnimationGroup()
animationGroup.animations = [animationForStrokeEnd, animationForStrokeStart]
animationGroup.duration = 0.9
animationGroup.repeatCount = MAXFLOAT
circleLayer.add(animationGroup, forKey: nil)
}
}
extension
import Foundation
import UIKit
extension MBProgressHUD{
class func showText(_ text:String) {
MBProgressHUD.showText(text, toView: nil)
}
class func showText(_ text:String, toView:UIView? ){
if text == "" {
return
}
var view = toView
if view == nil {
view = UIApplication.shared.windows.last
}
var hud = MBProgressHUD.HUDForView(view!)
if hud == nil {
hud = MBProgressHUD.showHUDAddedTo(view!, animated: true)
}
// let hud: MBProgressHUD = MBProgressHUD.showHUDAddedTo(view!, animated: true)
// Configure for text only and offset down
hud!.mode = .text
hud!.labelText = text
hud!.removeFromSuperViewOnHide = true
hud!.hide(true, afterDelay: 1)
}
class func showWait(_ message:String?)->MBProgressHUD{
let view = UIApplication.shared.windows.last
let hud: MBProgressHUD = MBProgressHUD.showHUDAddedTo(view!, animated: true)
hud.labelText = message
hud.removeFromSuperViewOnHide = true
hud.show(true)
return hud
}
class func showWait()->MBProgressHUD{
return MBProgressHUD.showWait(nil)
}
class func hideHUDForView(_ forView:UIView?){
var view = forView
if view == nil {
view = UIApplication.shared.windows.last
}
_ = self.hideHUDForView(view!, animated: true)
}
class func hideHUD(){
MBProgressHUD.hideHUDForView(nil)
}
}