MG--Swift遮照HUD 1
在项目中经常会遇到比较耗时的操作
比如,网络请求,IO读写操作,这个操作往往比较耗时,这个时候我们往往不需要用户操作,这个时候我们就应该提供一个蒙版遮照来防止用户操作,就需要用到下面的方法了,下面是通过协议的方式写的蒙版提示界面,我们一般每写的一个界面度会涉及到网络APi请求,所以我们可以写一个公共的基类,比如这里的BaseViewController,我们只需要它遵守协议,其他界面需要HUD提示的继承此控制器即可
2种遮照效果
代码实现如下
// 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
}
}
}