美文网首页
Swift3.0/4.0--MBProgressHUDForSw

Swift3.0/4.0--MBProgressHUDForSw

作者: 梦里风吹过 | 来源:发表于2017-04-05 20:12 被阅读723次

    MBProgress是我非常喜欢用的一个提示组件,GitHub上有更新到Swift2.0版本的(https://github.com/powfulhong/MBProgressHUDForSwift).
    奈何作者似乎并没有继续更新的意思,没办法只能手动更新了,直接上代码,希望对小伙伴们有所帮助.
    注:我只是针对Swift2.0版本的代码做了升级处理,并没有做任何改动,感谢jdgpowfulhong的无私奉献.

    代码地址: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)
        }
    }
    

    相关文章

      网友评论

          本文标题:Swift3.0/4.0--MBProgressHUDForSw

          本文链接:https://www.haomeiwen.com/subject/qiuxattx.html