MG--Swift遮照HUD 1

作者: Mg明明就是你 | 来源:发表于2022-01-14 21:30 被阅读0次

    MG--Swift遮照HUD 1

    在项目中经常会遇到比较耗时的操作

    比如,网络请求,IO读写操作,这个操作往往比较耗时,这个时候我们往往不需要用户操作,这个时候我们就应该提供一个蒙版遮照来防止用户操作,就需要用到下面的方法了,下面是通过协议的方式写的蒙版提示界面,我们一般每写的一个界面度会涉及到网络APi请求,所以我们可以写一个公共的基类,比如这里的BaseViewController,我们只需要它遵守协议,其他界面需要HUD提示的继承此控制器即可


    2种遮照效果

    image
    image

    代码实现如下

    //  MGCommonActivityIndicatorConfig.swift
    //  MGSDKDemo
    //  Created by LYM-mg on 2021/1/25.
    //  Copyright © 2021 . All rights reserved.
    
    
    import UIKit
    
    fileprivate let kIndicatorViewLength = CGFloat(155)
    //Common
    fileprivate let kCommonAnimationTime:Double = 0.24
    fileprivate let SpinningAnimationKey = "com.hsbc.loading.view.spinning.animation.key"
    fileprivate let CurveEndAnimationKey = "com.hsbc.loading.view.curve.end.animation.key"
    fileprivate let CurveStartAnimationKey = "com.hsbc.loading.view.curve.start.animation.key"
    
    fileprivate let kViewLength = CGFloat(45)
    fileprivate let kPartialCircleStrokeEnd = CGFloat(0.08)
    fileprivate let kBackgroundCornerRadius = CGFloat(0)
    fileprivate let kBackgroundViewPadding = CGFloat(10)
    fileprivate let kSpinningDuration = TimeInterval(3.24)
    fileprivate let kCircleLineWidth = CGFloat(3.5)
    fileprivate let kPartialCircleLineWidth = CGFloat(3)
    
    public enum ActivityIndicatorType {
        case blocking
        case unblocking(style: UIActivityIndicatorView.Style)
    }
    
    public protocol MGCommonActivityIndicatorConfig: class {
        var _indicatorContainerView: MGIndicatorContainerView? { get set }
        var _hudView: MGHUDView? { get set }
    }
    
    // MARK: Activity Indicator
    extension MGCommonActivityIndicatorConfig where Self: UIViewController {
        // MARK: - indicatorContainerView
        var indicatorContainerView: MGIndicatorContainerView {
            if let indicatorContainerView = _indicatorContainerView, let superView = indicatorContainerView.superview {
                superView.bringSubviewToFront(indicatorContainerView)
                return indicatorContainerView
            } else {
                let indicatorContainerView = MGIndicatorContainerView()
                indicatorContainerView.frame = CGRect(x: 0, y: 0, width: kIndicatorViewLength, height: kIndicatorViewLength)
                let view: UIView
                if let parentViewController = self.parent, parentViewController is BaseViewController {
                    view = parentViewController.view
                }
                else {
                    view = self.view
                }
                
                if let window = UIApplication.shared.keyWindow {
                    let frame = window.convert(window.frame, to: view)
                    let centerX = frame.origin.x + (UIScreen.main.bounds.width / 2)
                    let centerY = frame.origin.y  + (UIScreen.main.bounds.height / 2)
                    indicatorContainerView.center = CGPoint(x: centerX, y: centerY)
                } else {
                    indicatorContainerView.center = view.center
                    
                    if #available(iOS 11, *) {
                        indicatorContainerView.center.y -= self.navigationController == nil ? 0 : self.view.safeAreaInsets.top
                    }
                        
                    else {
                        indicatorContainerView.center.y -= self.navigationController == nil ? 0 : 64
                    }
                    
                    indicatorContainerView.center.y += self.topLayoutGuide.length
                }
                view.addSubview(indicatorContainerView)
                
                indicatorContainerView.indicatorView.hidesWhenStopped = true
                _indicatorContainerView = indicatorContainerView
                return indicatorContainerView
            }
        }
        
        public func showActivityIndicator(_ type: ActivityIndicatorType = .blocking, backgroundStyle: MGIndicatorView.SpinBackgroundStyle = .white, showInParnetViewControllerIfPossible: Bool = true, completion: ((Bool) -> Void)? = nil) {
            if let parentViewController = self.parent as? BaseViewController, showInParnetViewControllerIfPossible == true {
                parentViewController.showActivityIndicator()
                return
            }
            
            switch type {
                case .blocking:
                    self.indicatorContainerView.indicatorView.setBlocking(self.view, type: type)
                default: break
            }
            
            self.indicatorContainerView.configLayout(backgroundStyle)
            
            self.indicatorContainerView.startAnimating(backgroundStyle, completion: completion)
        }
        
        public func hideActivityIndicator(_ hideInParnetViewControllerIfPossible: Bool = true) {
            if let parentViewController = self.parent as? BaseViewController, hideInParnetViewControllerIfPossible == true {
                parentViewController.hideActivityIndicator()
                return
            }
            
            self.indicatorContainerView.stopAnimation({ [weak self] finished in
                guard let strongSelf = self else { return }
                strongSelf.indicatorContainerView.indicatorView.setBlocking(strongSelf.view, type: .unblocking(style: .medium))
            })
        }
        
        public func showActivityIndicatorForNav() {
            if let nav = self.navigationController as? MGNavigationController {
                nav.showActivityIndicator(.blocking)
                nav.navigationBar.isUserInteractionEnabled = false
                nav.view.isUserInteractionEnabled = false
            } else {
                self.showActivityIndicator(.blocking)
            }
        }
        
        public func hideActivityIndicatorForNav() {
            if let nav = self.navigationController as? MGNavigationController {
                nav.hideActivityIndicator()
                nav.navigationBar.isUserInteractionEnabled = true
                nav.view.isUserInteractionEnabled = true
            } else {
                self.hideActivityIndicator()
            }
        }
        
        
        // MARK: - HUD
        var hudView: MGHUDView {
            if let hudView = _hudView, let superView = hudView.superview {
                superView.bringSubviewToFront(hudView)
                return hudView
            } else {
                let hudView = MGHUDView(frame: self.view.frame)
                let view: UIView
                if let parentViewController = self.parent, parentViewController is BaseViewController {
                    view = parentViewController.view
                }
                else {
                    view = self.view
                }
                
                view.addSubview(hudView)
                _hudView = hudView
                return hudView
            }
        }
        
        public func showMGHUD(_ type: ActivityIndicatorType = .blocking, hudType: MGHUDType = .MGHUDTypeCenter, completion: ((Bool) -> Void)? = nil) {
            self.hudView.configHUDType(type: hudType)
            
            switch type {
                case .blocking:
                    self.hudView.setBlocking(self.view, type: type)
                default: break
            }
            self.hudView.startAnimating()
        }
        
        public func hideMGHUD() {
            self.hudView.stopAnimating { [weak self] in
                guard let strongSelf = self else { return }
                strongSelf.hudView.setBlocking(strongSelf.view, type: .unblocking(style: .medium))
            }
        }
        
    }
    
    
    
    // MARK: - MGIndicatorContainerView
    public class MGIndicatorContainerView: UIView {
        
        weak var backgroundContainerView: UIView!
        weak var backgroundOverlayView: UIView!
        weak var containerView: UIView!
        
        weak var indicatorView: MGIndicatorView!
        weak var titleLabel: UILabel!
        
        weak var blurView: UIVisualEffectView!
        
        var isAnimating: Bool = false
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            self.commonInit()
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    extension MGIndicatorContainerView {
        fileprivate func commonInit() {
            self.isHidden = true
            
            let blurView = UIVisualEffectView(effect: nil)
            blurView.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(blurView)
            self.blurView = blurView
            
            let backgroundContainerView = UIView()
            backgroundContainerView.translatesAutoresizingMaskIntoConstraints = false
            backgroundContainerView.clipsToBounds = true
            self.addSubview(backgroundContainerView)
            self.backgroundContainerView = backgroundContainerView
            
            let backgroundOverlayView = UIView()
            backgroundOverlayView.translatesAutoresizingMaskIntoConstraints = false
            backgroundOverlayView.backgroundColor = UIColor(red: 0xA7/255.0, green: 0xA7/255.0, blue: 0xA7/255.0, alpha: 1.0)
            backgroundOverlayView.alpha = 0.25
            self.backgroundContainerView.addSubview(backgroundOverlayView)
            self.backgroundOverlayView = backgroundOverlayView
            
            let containerView = UIView()
            containerView.translatesAutoresizingMaskIntoConstraints = false
            containerView.backgroundColor = UIColor.clear
            self.backgroundContainerView.addSubview(containerView)
            self.containerView = containerView
            
            let indicatorView = MGIndicatorView()
            indicatorView.translatesAutoresizingMaskIntoConstraints = false
            self.containerView.addSubview(indicatorView)
            self.indicatorView = indicatorView
            
            let titleLabel = UILabel()
            titleLabel.translatesAutoresizingMaskIntoConstraints = false
            titleLabel.font = UIFont(name: "UniversNextforHSBC-Regular", size: 12)
            self.containerView.addSubview(titleLabel)
            self.titleLabel = titleLabel
            
            self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[backgroundContainerView]|", options: [], metrics: nil, views: ["backgroundContainerView": backgroundContainerView]))
            self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[backgroundContainerView]|", options: [], metrics: nil, views: ["backgroundContainerView": backgroundContainerView]))
            
            self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[blurView]|", options: [], metrics: nil, views: ["blurView": blurView]))
            self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[blurView]|", options: [], metrics: nil, views: ["blurView": blurView]))
            
            self.backgroundContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[backgroundOverlayView]|", options: [], metrics: nil, views: ["backgroundOverlayView": backgroundOverlayView]))
            self.backgroundContainerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[backgroundOverlayView]|", options: [], metrics: nil, views: ["backgroundOverlayView": backgroundOverlayView]))
            
            self.backgroundContainerView.addConstraint(NSLayoutConstraint(item: self.containerView, attribute: .centerX, relatedBy: .equal, toItem: self.backgroundContainerView, attribute: .centerX, multiplier: 1, constant: 0))
            self.backgroundContainerView.addConstraint(NSLayoutConstraint(item: self.containerView, attribute: .centerY, relatedBy: .equal, toItem: self.backgroundContainerView, attribute: .centerY, multiplier: 1, constant: 0))
            
            self.containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[indicatorView(==45)]-20-[titleLabel]|", options: [], metrics: nil, views: ["indicatorView": indicatorView, "titleLabel": titleLabel]))
            self.containerView.addConstraint(NSLayoutConstraint(item: self.indicatorView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 45))
            self.containerView.addConstraint(NSLayoutConstraint(item: self.indicatorView, attribute: .centerX, relatedBy: .equal, toItem: self.containerView, attribute: .centerX, multiplier: 1, constant: 0))
            self.containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[titleLabel]|", options: [], metrics: nil, views: [
                "titleLabel": titleLabel]))
        }
    }
    
    extension MGIndicatorContainerView {
        func configLayout(_ backgroundType: MGIndicatorView.SpinBackgroundStyle) {
            switch backgroundType {
            case .white:
                self.backgroundOverlayView.backgroundColor = UIColor(red: 0xA7/255.0, green: 0xA7/255.0, blue: 0xA7/255.0, alpha: 1.0)
                self.backgroundOverlayView.alpha = 0.25
                self.indicatorView.strokeColor = UIColor(red: 0x5C/255.0, green: 0x5C/255.0, blue: 0x5C/255.0, alpha: 1.0)
                self.titleLabel.textColor = UIColor(red: 0x5C/255.0, green: 0x5C/255.0, blue: 0x5C/255.0, alpha: 1.0)
            case .black:
                self.backgroundOverlayView.backgroundColor = UIColor(white: 0, alpha: 0.25)
                self.indicatorView.strokeColor = .white
                self.titleLabel.textColor = .white
            }
            
            self.titleLabel.text = "Loading"
        }
    }
    
    extension MGIndicatorContainerView {
        func startAnimating(_ backgroundType: MGIndicatorView.SpinBackgroundStyle, completion: ((Bool) -> Void)? = nil) {
            if isAnimating {
                DispatchQueue.main.asyncAfter(deadline: .now() + kCommonAnimationTime) {
                    self.startAnimating(backgroundType, completion: completion)
                }
                return
            }
            isAnimating = true
            let effect: UIBlurEffect!
            switch backgroundType {
            case .white:
                effect = UIBlurEffect(style: .light)
            case .black:
                effect = UIBlurEffect(style: .dark)
            }
            
            self.indicatorView.startAnimating()
            self.isHidden = false
            self.backgroundContainerView.alpha = 0
            UIView.animate(withDuration: kCommonAnimationTime, animations: {
                self.backgroundContainerView.alpha = 1
                self.blurView.effect = effect
                self.isAnimating = false
            }, completion: completion)
        }
        
        func stopAnimation(_ completion: ((Bool) -> ())? = nil) {
            if isAnimating {
                DispatchQueue.main.asyncAfter(deadline: .now() + kCommonAnimationTime*2) {
                    self.stopAnimation(completion)
                }
                return
            }
            self.backgroundContainerView.alpha = 1
            isAnimating = true
            UIView.animate(withDuration: kCommonAnimationTime, animations: {
                self.backgroundContainerView.alpha = 0
                self.blurView.effect = nil
            }, completion: { (finished) in
                self.isHidden = true
                self.indicatorView.stopAnimating()
                self.isAnimating = false
                completion?(finished)
            })
        }
    }
    
    
    // MARK: - MGIndicatorView
    @IBDesignable open class MGIndicatorView: UIView {
        public enum SpinBackgroundStyle {
            case white
            case black
        }
        
        @IBInspectable open var lineWidth: CGFloat = kPartialCircleLineWidth {
            didSet {
                self.partialCirclePathLayer.lineWidth = self.lineWidth
            }
        }
        fileprivate(set) open var isAnimating = false
        @IBInspectable open var autoStartAnimating: Bool = false {
            didSet {
                if self.autoStartAnimating && self.superview != nil {
                    self.animate(true)
                }
            }
        }
        @IBInspectable open var hidesWhenStopped: Bool = false
        @IBInspectable open var strokeColor: UIColor = UIColor(red: 0x5C/255.0, green: 0x5C/255.0, blue: 0x5C/255.0, alpha: 1.0) {
            didSet {
                self.partialCirclePathLayer.strokeColor = self.strokeColor.cgColor
            }
        }
        
        fileprivate var partialCirclePathLayer = CAShapeLayer()
        fileprivate var circlePathLayer = CAShapeLayer()
        weak var spinBackgroundView: UIView!
        fileprivate weak var imageView: UIImageView!
        open var loadingImage: UIImage? {
            didSet {
                self.imageView.image = self.loadingImage
            }
        }
        
        fileprivate var needReloadCurveAnimation = false
        fileprivate var isFirstLaunch = true
        
        deinit {
            NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
        }
        
        override public init(frame: CGRect) {
            super.init(frame: frame)
            configure()
        }
        
        required public init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            configure()
        }
        
        override open func layoutSubviews() {
            super.layoutSubviews()
            self.partialCirclePathLayer.frame = bounds
            self.partialCirclePathLayer.path = self.circlePath().cgPath
            self.partialCirclePathLayer.strokeStart = 0
            self.partialCirclePathLayer.strokeEnd = 0
            
            self.circlePathLayer.frame = bounds
            self.circlePathLayer.path = self.circlePath().cgPath
            var circleFrame = self.circleFrame()
            let radius = min(self.partialCirclePathLayer.bounds.size.width, self.partialCirclePathLayer.bounds.size.height) / 2
            circleFrame = circleFrame.insetBy(dx: radius/2, dy: radius/2)
            let spinBackgroundViewLength = kViewLength + kBackgroundViewPadding * 2
            self.spinBackgroundView.frame = CGRect(x: -kBackgroundViewPadding, y: -kBackgroundViewPadding, width: spinBackgroundViewLength, height: spinBackgroundViewLength)
            self.imageView.frame = circleFrame
            
            self.isFirstLaunch = false
        }
        
        override open func willMove(toSuperview newSuperview: UIView?) {
            super.willMove(toSuperview: newSuperview)
            
            if newSuperview != nil {
                if self.autoStartAnimating {
                    self.animate(true)
                }
            } else {
                self.animate(false)
            }
        }
        
        override open func willMove(toWindow newWindow: UIWindow?) {
            super.willMove(toWindow: newWindow)
            
            if self.needReloadCurveAnimation {
                self.needReloadCurveAnimation = false
                
                self.resetCurveAnimation()
            }
        }
        
        open func startAnimating() {
            self.animate(true)
        }
        
        open func stopAnimating() {
            self.animate(false)
        }
        
        fileprivate func animate(_ animated: Bool) {
            if animated {
                self.isHidden = false
                
                if self.isAnimating == false {
                    self.createAnimationLayer()
                }
                
                self.isAnimating = true
            } else {
                self.isAnimating = false
                if self.hidesWhenStopped {
                    self.isHidden = true
                }
                
                self.partialCirclePathLayer.removeAnimation(forKey: SpinningAnimationKey)
                self.partialCirclePathLayer.removeAnimation(forKey: CurveEndAnimationKey)
                self.partialCirclePathLayer.removeAnimation(forKey: CurveStartAnimationKey)
            }
        }
        
        func removeAllAnimationLayer() {
            self.partialCirclePathLayer.removeAnimation(forKey: SpinningAnimationKey)
            self.partialCirclePathLayer.removeAnimation(forKey: CurveEndAnimationKey)
            self.partialCirclePathLayer.removeAnimation(forKey: CurveStartAnimationKey)
        }
        
        func createAnimationLayer() {
            self.partialCirclePathLayer.strokeStart = 0
            self.partialCirclePathLayer.strokeEnd = 0
            
            let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
            rotateAnimation.fromValue = NSNumber(value: 0)
            rotateAnimation.toValue = NSNumber(value: 2 * Double.pi)
            rotateAnimation.duration = kSpinningDuration
            rotateAnimation.isRemovedOnCompletion = false // prevent from getting remove when app enter background or view disappear
            rotateAnimation.repeatCount = Float.infinity
            self.partialCirclePathLayer.add(rotateAnimation, forKey: SpinningAnimationKey)
            
            self.createCurveChangeAnimationLayer(self.partialCirclePathLayer)
        }
        
        fileprivate func createCurveChangeAnimationLayer(_ layer: CALayer) {
            let curveEndChangeAnimation = CABasicAnimation(keyPath: "strokeEnd")
            curveEndChangeAnimation.fromValue = 0
            curveEndChangeAnimation.toValue = 1
            curveEndChangeAnimation.duration = 1.7
            curveEndChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
            curveEndChangeAnimation.isRemovedOnCompletion = false
            curveEndChangeAnimation.repeatCount = 0
            curveEndChangeAnimation.isCumulative = true
            curveEndChangeAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
            self.partialCirclePathLayer.add(curveEndChangeAnimation, forKey: CurveEndAnimationKey)
            
            let curveStartChangeAnimation = CABasicAnimation(keyPath: "strokeStart")
            curveStartChangeAnimation.fromValue = self.partialCirclePathLayer.strokeStart
            self.partialCirclePathLayer.strokeStart = 0
            self.partialCirclePathLayer.strokeEnd = 0
            curveStartChangeAnimation.toValue = 1
            curveStartChangeAnimation.beginTime = CACurrentMediaTime() + 0.24
            curveStartChangeAnimation.duration = 1.7
            curveStartChangeAnimation.isRemovedOnCompletion = false
            curveStartChangeAnimation.delegate = self
            curveStartChangeAnimation.repeatCount = 0
            curveStartChangeAnimation.isCumulative = true
            curveStartChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
            curveStartChangeAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
            self.partialCirclePathLayer.add(curveStartChangeAnimation, forKey: CurveStartAnimationKey)
        }
        
        fileprivate func circleFrame() -> CGRect {
            // Align center
            let diameter = min(self.partialCirclePathLayer.bounds.size.width, self.partialCirclePathLayer.bounds.size.height)
            var circleFrame = CGRect(x: 0, y: 0, width: diameter, height: diameter)
            circleFrame.origin.x = self.partialCirclePathLayer.bounds.midX - circleFrame.midX
            circleFrame.origin.y = self.partialCirclePathLayer.bounds.midY - circleFrame.midY
            
            // offset lineWidth
            let inset = self.partialCirclePathLayer.lineWidth / 2
            circleFrame = circleFrame.insetBy(dx: inset, dy: inset)
            
            return circleFrame
        }
        
        fileprivate func circlePath() -> UIBezierPath {
            return UIBezierPath(ovalIn: self.circleFrame())
        }
        
        fileprivate func configure() {
            self.bounds = CGRect(x: 0, y: 0, width: kViewLength, height: kViewLength)
            self.backgroundColor = UIColor.clear
            
            let spinBackgroundView = UIView()
            spinBackgroundView.backgroundColor = UIColor(white: 1, alpha: 0.8)
            spinBackgroundView.layer.cornerRadius = kBackgroundCornerRadius
            spinBackgroundView.isHidden = true
            self.addSubview(spinBackgroundView)
            self.spinBackgroundView = spinBackgroundView
            
            let imageView = UIImageView()
            imageView.contentMode = .scaleAspectFit
            imageView.backgroundColor = UIColor.clear
            self.addSubview(imageView)
            self.imageView = imageView
            
    //        self.circlePathLayer.frame = bounds
    //        self.circlePathLayer.backgroundColor = UIColor.clear.cgColor
    //        self.circlePathLayer.lineWidth = kCircleLineWidth
    //        self.circlePathLayer.fillColor = UIColor.clear.cgColor
    //        self.circlePathLayer.strokeColor = defaultLayout().colorWithColorIdentifier(ColorIdentifier.divider).cgColor
    //        self.circlePathLayer.opacity = 0.8
    //        layer.addSublayer(self.circlePathLayer)
            
            self.setUpPartialCirclePathLayer()
            self.layoutSubviews()
        }
        
        func setUpPartialCirclePathLayer() {
            self.partialCirclePathLayer.frame = bounds
            self.partialCirclePathLayer.lineWidth = kPartialCircleLineWidth
            self.partialCirclePathLayer.fillColor = UIColor.clear.cgColor
            self.partialCirclePathLayer.strokeColor = self.strokeColor.cgColor
            self.partialCirclePathLayer.strokeStart = 0
            self.partialCirclePathLayer.strokeEnd = 0
            self.partialCirclePathLayer.backgroundColor = UIColor.clear.cgColor
            layer.addSublayer(self.partialCirclePathLayer)
        }
        
        fileprivate func resetCurveAnimation() {
            self.partialCirclePathLayer.strokeStart = 0
            self.partialCirclePathLayer.strokeEnd = 0
            
            self.partialCirclePathLayer.removeAnimation(forKey: CurveEndAnimationKey)
            self.partialCirclePathLayer.removeAnimation(forKey: CurveStartAnimationKey)
            
            self.createCurveChangeAnimationLayer(self.partialCirclePathLayer)
        }
    }
    
    extension MGIndicatorView: CAAnimationDelegate {
        public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
            if flag {
                self.resetCurveAnimation()
            } else {
                if self.isAnimating {
                    self.needReloadCurveAnimation = true
                }
            }
        }
    }
    
    // MARK: - Blocking handling
    extension MGIndicatorView {
        func setBlocking(_ view: UIView, type: ActivityIndicatorType) {
            switch type {
            case .blocking:
                view.isUserInteractionEnabled = false
            default:
                view.isUserInteractionEnabled = true
            }
        }
    }
    
    class BaseViewController: UIViewController, MGCommonActivityIndicatorConfig {
        var _hudView: MGHUDView?
        var _indicatorContainerView: MGIndicatorContainerView?
    }
    
    class MGNavigationController: UINavigationController, MGCommonActivityIndicatorConfig {
        var _indicatorContainerView: MGIndicatorContainerView?
        var _hudView: MGHUDView?
    }
    
    
    public enum MGHUDType {
        case MGHUDTypeCenter     //居中
        case MGHUDTypeFullScren  //全屏
    }
    
    public class MGHUDView: UIView {
        fileprivate var hudType: MGHUDType = .MGHUDTypeCenter {
            didSet {
                if hudType == .MGHUDTypeCenter {
                    self.setupLoadingBackView(frame: CGRect(x: (self.frame.size.width-160)/2, y: (self.frame.size.height-160)/2-20, width: 160, height: 160), title: "")
                    self.loadingBackView?.layer.cornerRadius = 10;
                    self.loadingBackView?.backgroundColor = UIColor(red: 222/255.0, green: 222/255.0, blue: 222/255.0, alpha: 0.8)
                }else {
                    self.setupLoadingBackView(frame: CGRect(x: (self.frame.size.width-160)/2, y: self.frame.size.height/3, width: 160, height: 160), title: "")
                    self.backgroundColor = .white
                }
            }
        }
        var loadingBackView: UIView?
        var label: UILabel?
        var angle: Double = 0
        var titleString: String?
        var isAnimating: Bool = false
        var stepNumber: Int = 0
        var timer: Timer?
        
        var shapView: UIImageView?
        var shadowView: UIImageView?
        
        var fromValue: Float = 0
        var toValue: Float = 0
        var scalefromValue: Float = 0
        var scaletoValue: Float = 0
        
        deinit {
            self.timer?.invalidate()
            self.timer = nil
        }
        
        func setupLoadingBackView(frame: CGRect, title: String) {
            self.loadingBackView = UIView(frame: frame)
            self.addSubview(self.loadingBackView!)
            self.titleString = title;
            self.step()
        }
        
        func step() {
            guard let loadingBackView = self.loadingBackView  else {
                return
            }
            var l_width = loadingBackView.frame.size.width
            var l_height = loadingBackView.frame.size.height
            var isCenter = false
            if (self.hudType == .MGHUDTypeCenter) {
                
                l_width-=15;
                l_height-=15;
                isCenter = true;
            }
            shapView = UIImageView();
            shapView?.frame = CGRect(x: (l_width-35)/2+(isCenter ? 7.5 : 0), y: (isCenter ? 10 : 0), width: 35, height: 35)
            shapView?.image = UIImage(named: "loading_square")
            shapView?.contentMode = .scaleAspectFit;
            loadingBackView.addSubview(shapView!)
            
            //阴影
            shadowView = UIImageView()
            shadowView?.frame = CGRect(x: l_width/2-40/2+(isCenter ? 7.5:0), y: l_height-4-30, width: 40, height: 4)
            shadowView?.image = UIImage(named: "loading_shadow")
            loadingBackView.addSubview(shadowView!)
            
            label = UILabel()
            label?.frame = CGRect(x: (isCenter ? 7.5 : 0), y: l_height-20, width: l_width, height: 20)
            label?.textColor = UIColor(red: 55, green: 55, blue: 55, alpha: 1.0);
            label?.textAlignment = .center
            label?.font = UIFont.systemFont(ofSize: 13)
            label?.text = "加载中...";
            loadingBackView.addSubview(label!)
    
           if (self.hudType == .MGHUDTypeCenter) {
                
            }else {
                shapView?.backgroundColor = .white
            }
            
            fromValue = Float(shapView!.frame.size.height/2+(isCenter ? 10 : 0));
            toValue =  Float(l_height - 30 - shapView!.frame.size.height/2 - shadowView!.frame.size.height)
            
            
            scalefromValue = 0.3
            scaletoValue = 1.0
            self.angle = 0;
            self.alpha = 0;
        }
        
        func scaleAnimation(_ fromeValue: Float, toValue: Float, timingFunction tf: String?) {
            //缩放
            let sanimation = CABasicAnimation()
            sanimation.keyPath = "transform.scale"
            sanimation.fromValue = NSNumber(value: fromeValue)
            sanimation.toValue = NSNumber(value: toValue)
            sanimation.duration = 0.5
    
            sanimation.fillMode = .forwards
            sanimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: tf ?? CAMediaTimingFunctionName.easeIn.rawValue))
            sanimation.isRemovedOnCompletion = false
    
            shadowView?.layer.add(sanimation, forKey: "shadow")
        }
        
        @objc func animateNextStep() {
            switch stepNumber {
                case 0:
                    loadingAnimation(fromValue, toValue: toValue, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
                    scaleAnimation(scalefromValue, toValue: scaletoValue, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
                break;
                case 1:
                    loadingAnimation(
                        toValue,
                        toValue: fromValue,
                        timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
                    scaleAnimation(scaletoValue, toValue: scalefromValue, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
    //                stepNumber = -1
                break;
                case 2:
                    shapView!.image = UIImage(named: "loading_square")
                    loadingAnimation(
                        fromValue,
                        toValue: toValue,
                        timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
                break;
                case 3:
                    loadingAnimation(
                    toValue,
                    toValue: fromValue,
                    timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
                    stepNumber = -1
                break;
                default: break
            }
            stepNumber += 1
        }
            
        func loadingAnimation(_ fromValue: Float, toValue: Float, timingFunction tf: String) {
            let panimation = CABasicAnimation()
            panimation.keyPath = "position.y"
            panimation.fromValue = NSNumber(value: fromValue)
            panimation.toValue = NSNumber(value: toValue)
            panimation.duration = 0.5
            panimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: tf))
            
            //旋转
            let ranimation = CABasicAnimation()
            ranimation.keyPath = "transform.rotation"
    
            ranimation.fromValue = NSNumber(value: angle)
            ranimation.toValue = NSNumber(value: angle + Double.pi/2)
            angle += Double.pi/2
            ranimation.duration = 0.5
            ranimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName(rawValue: tf))
            
            //组合
            let group = CAAnimationGroup()
            group.animations = [panimation, ranimation]
            group.duration = 0.5
            group.beginTime = 0
            group.fillMode = .forwards
            group.isRemovedOnCompletion = false
            
            shapView!.layer.add(group, forKey: "basic")
        }
        
        public func configHUDType(type: MGHUDType) {
            self.hudType = type
            label?.text = "加载中...";
        }
        public func startAnimating() {
    
            if !isAnimating, timer == nil {
                isAnimating = true
                self.alpha = 1
                timer = Timer(timeInterval: 0.5, target: self, selector: #selector(animateNextStep), userInfo: nil, repeats: true)
                RunLoop.main.add(timer!, forMode: RunLoop.Mode.common)
            }
        }
    
        public func stopAnimating(_ completion: (() -> ())? = nil) {
    
            isAnimating = false
            timer?.invalidate()
            timer = nil
    
            stepNumber = 0
    
            alpha = 0
            
            shapView?.layer.removeAllAnimations()
            shadowView?.layer.removeAllAnimations()
            shapView?.image = UIImage(named: "loading_square")
            completion?()
            self.removeFromSuperview()
        }
        
        public func setBlocking(_ view: UIView, type: ActivityIndicatorType) {
            switch type {
            case .blocking:
                view.isUserInteractionEnabled = false
            default:
                view.isUserInteractionEnabled = true
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:MG--Swift遮照HUD 1

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