MG--Swift遮照HUD 2
比如网络请求IO读写操作这个操作往往比较耗时这个时候我们往往不需要用户操作这个时候我们就应该提供一个蒙版遮照来防止用户操作就需要用到下面的方法了下面是写的蒙版提示界面我们一般每写的一个界面度会涉及到网络APi请求所以需要HUD
2种遮照效果
代码实现如下
//
// MGSquaresAnimationView.swift
// MGSDKDemo
// Created by LYM-mg on 2021/1/27.
// Copyright © 2021 LYM-mg. All rights reserved.
//
import UIKit
public enum MGSquaresAnimationViewType {
case Square(animationLayerTintColor: UIColor, squareSize: CGFloat)
case Circle(ballWidth: CGFloat)
}
public class MGSquaresAnimationView: UIView {
convenience init(frame: CGRect = UIScreen.main.bounds, animationViewType: MGSquaresAnimationViewType = .Circle(ballWidth: 13)) {
self.init(frame: frame)
switch animationViewType {
case .Circle(let ballWidth):
self._ballWidth = ballWidth
self.initBallView()
break
case .Square(let animationLayerTintColor, let squareSize):
self.initSquareView()
self.animationLayer.frame = self.bounds
self.animationLayerTintColor = animationLayerTintColor
self.squareSize = squareSize
self.setupAnimation()
let tintColorRef = animationLayerTintColor.cgColor
animationLayer.backgroundColor = tintColorRef
break
}
self.animationViewType = animationViewType
}
public override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
print("\(self)--deinit")
}
// MARK: - Square
fileprivate var animationLayer: CALayer = CALayer()
fileprivate var isAnimating: Bool = false
fileprivate var animationLayerTintColor: UIColor = .white {
didSet {
let tintColorRef = animationLayerTintColor.cgColor
for subLayer in animationLayer.sublayers ?? [] {
subLayer.backgroundColor = tintColorRef
if subLayer is CAShapeLayer {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = tintColorRef
shapeLayer.fillColor = tintColorRef
}
}
}
}
fileprivate var squareSize: CGFloat = 60 {
didSet {
self.setupAnimation()
}
}
fileprivate var animationViewType: MGSquaresAnimationViewType = .Circle(ballWidth: 13)
func initSquareView() {
// isUserInteractionEnabled = false
isHidden = false
layer.addSublayer(animationLayer)
}
func startAnimating() {
switch animationViewType {
case .Circle(_):
startPathAnimation()
break
case .Square(_ , _):
if (animationLayer.sublayers != nil) {
setupAnimation()
}
isHidden = false
animationLayer.speed = 1.0
break
}
isAnimating = true
}
func stopAnimating() {
switch animationViewType {
case .Circle(_):
ball1.layer.removeAllAnimations()
ball1.removeFromSuperview()
ball2.layer.removeAllAnimations()
ball2.removeFromSuperview()
ball3.layer.removeAllAnimations()
ball3.removeFromSuperview()
case .Square(animationLayerTintColor , squareSize):
animationLayer.speed = 0.0
isHidden = true
default:
break
}
isAnimating = false
}
func setupAnimation() {
animationLayer.sublayers = nil
setupAnimation(layer: animationLayer, with: CGSize(width: self.squareSize, height: self.squareSize), tintColor: self.animationLayerTintColor)
animationLayer.speed = 0.0
}
func setupAnimation(layer: CALayer, with size: CGSize, tintColor: UIColor) {
let beginTime = TimeInterval(CACurrentMediaTime())
let squareSize = floor(size.width / 4.0)
let oX: CGFloat = (layer.bounds.size.width - size.width) / 2.0
let oY: CGFloat = (layer.bounds.size.height - size.height) / 2.0
let colors = [
UIColor(red: 0.880, green: 0.409, blue: 0.195, alpha: 1),
UIColor(red: 0.137, green: 0.412, blue: 0.663, alpha: 1),
UIColor(red: 0.810, green: 0.709, blue: 0.115, alpha: 1),
UIColor(red: 0.537, green: 0.492, blue: 0.363, alpha: 1)
]
for i in 0..<5 {
let square = CALayer()
square.frame = CGRect(x: oX, y: oY, width: squareSize, height: squareSize)
square.anchorPoint = CGPoint(x: 0.5, y: 0.5)
square.backgroundColor = colors[i].cgColor
square.shouldRasterize = true
square.rasterizationScale = UIScreen.main.scale
let transformAnimation = createKeyframeAnimation(withKeyPath: "transform")
transformAnimation.duration = 1.6
transformAnimation.beginTime = beginTime - (Double(i) * (transformAnimation.duration) / 4.0)
transformAnimation.repeatCount = MAXFLOAT
transformAnimation.keyTimes = [NSNumber(value: 0.0), NSNumber(value: 0.25), NSNumber(value: 0.50), NSNumber(value: 0.75), NSNumber(value: 1.0)]
transformAnimation.timingFunctions = [
CAMediaTimingFunction(name: .easeInEaseOut),
CAMediaTimingFunction(name: .easeInEaseOut),
CAMediaTimingFunction(name: .easeInEaseOut),
CAMediaTimingFunction(name: .easeInEaseOut),
CAMediaTimingFunction(name: .easeInEaseOut)
]
var t1 = CATransform3DMakeTranslation(size.width - squareSize, 0.0, 0.0)
t1 = CATransform3DRotate(t1, degreesToRadians(-90.0), 0.0, 0.0, 1.0)
t1 = CATransform3DScale(t1, 0.7, 0.7, 1.0)
var t2 = CATransform3DMakeTranslation(size.width - squareSize, size.height - squareSize, 0.0)
t2 = CATransform3DRotate(t2, degreesToRadians(-180.0), 0.0, 0.0, 1.0)
t2 = CATransform3DScale(t2, 1.0, 1.0, 1.0)
var t3 = CATransform3DMakeTranslation(0.0, size.height - squareSize, 0.0)
t3 = CATransform3DRotate(t3, degreesToRadians(-270.0), 0.0, 0.0, 1.0)
t3 = CATransform3DScale(t3, 0.7, 0.7, 1.0)
var t4 = CATransform3DMakeTranslation(0.0, 0.0, 0.0)
t4 = CATransform3DRotate(t4, degreesToRadians(-360.0), 0.0, 0.0, 1.0)
t4 = CATransform3DScale(t4, 1.0, 1.0, 1.0)
transformAnimation.values = [
NSValue(caTransform3D: CATransform3DIdentity),
NSValue(caTransform3D: t1),
NSValue(caTransform3D: t2),
NSValue(caTransform3D: t3),
NSValue(caTransform3D: t4)
]
layer.addSublayer(square)
square.add(transformAnimation, forKey: "animation")
}
}
private func degreesToRadians(_ degrees: Double) -> CGFloat {
return CGFloat((degrees) / 180.0 * Double.pi)
}
private func createAnimationGroup() -> CAAnimationGroup {
let animationGroup = CAAnimationGroup()
animationGroup.isRemovedOnCompletion = false
return animationGroup
}
private func createBasicAnimation(withKeyPath keyPath: String?) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: keyPath)
animation.isRemovedOnCompletion = false
return animation
}
private func createKeyframeAnimation(withKeyPath keyPath: String?) -> CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath: keyPath)
animation.isRemovedOnCompletion = false
return animation
}
// MARK: - Circle
var ball1: UIView = UIView()
var ball2: UIView = UIView()
var ball3: UIView = UIView()
var _ballWidth: CGFloat = 13
var ballContainer: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
func initBallView() {
ballContainer.frame = CGRect(x: 0, y: 0, width: 120, height: 120)
ballContainer.center = CGPoint(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0)
ballContainer.layer.cornerRadius = 10.0
ballContainer.layer.masksToBounds = true
ballContainer.backgroundColor = UIColor.clear
addSubview(ballContainer)
let margin: CGFloat = 3.0
ball1 = UIView(frame: CGRect(x: 0, y: 0, width: _ballWidth, height: _ballWidth))
ball1.center = CGPoint(x: _ballWidth / 2.0 + margin, y: ballContainer.bounds.size.height / 2.0)
ball1.layer.cornerRadius = _ballWidth / 2.0
ball1.backgroundColor = UIColor(red: 54 / 255.0, green: 136 / 255.0, blue: 250 / 255.0, alpha: 1)
ballContainer.contentView.addSubview(ball1)
ball2 = UIView(frame: CGRect(x: 0, y: 0, width: _ballWidth, height: _ballWidth))
ball2.center = CGPoint(x: ballContainer.bounds.size.width / 2.0, y: ballContainer.bounds.size.height / 2.0)
ball2.layer.cornerRadius = _ballWidth / 2.0
ball2.backgroundColor = UIColor(red: 100 / 255.0, green: 100 / 255.0, blue: 100 / 255.0, alpha: 1)
ballContainer.contentView.addSubview(ball2)
ball3 = UIView(frame: CGRect(x: 0, y: 0, width: _ballWidth, height: _ballWidth))
ball3.center = CGPoint(x: ballContainer.bounds.size.width - _ballWidth / 2.0 - margin, y: ballContainer.bounds.size.height / 2.0)
ball3.layer.cornerRadius = _ballWidth / 2.0
ball3.backgroundColor = UIColor(red: 234 / 255.0, green: 67 / 255.0, blue: 69 / 255.0, alpha: 1)
ballContainer.contentView.addSubview(ball3)
}
func startPathAnimation() {
let ballScale: CGFloat = 1.3
//-------第一个球的动画
let width = ballContainer.bounds.size.width
//小圆半径
let r: CGFloat = (ball1.bounds.size.width) * ballScale / 2.0
//大圆半径
let R = (width / 2 + r) / 2.0
let path1 = UIBezierPath()
path1.move(to: ball1.center)
//画大圆
path1.addArc(withCenter: CGPoint(x: R + r, y: width / 2), radius: R, startAngle: .pi, endAngle: .pi * 2, clockwise: false)
//画小圆
let path1_1 = UIBezierPath()
path1_1.addArc(withCenter: CGPoint(x: width / 2, y: width / 2), radius: r * 2, startAngle: .pi * 2, endAngle: .pi, clockwise: false)
path1.append(path1_1)
//回到原处
path1.addLine(to: ball1.center)
//执行动画
let positionAnimation = CAKeyframeAnimation(keyPath: "position")
positionAnimation.path = path1.cgPath
positionAnimation.isRemovedOnCompletion = false
positionAnimation.repeatCount = MAXFLOAT
positionAnimation.duration = 1.6
positionAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
ball1.layer.add(positionAnimation, forKey: "animation1")
//-------第三个球的动画
let path3 = UIBezierPath()
path3.move(to: ball3.center)
//画大圆
path3.addArc(withCenter: CGPoint(x: width - (R + r), y: width / 2), radius: R, startAngle: 2 * .pi, endAngle: .pi, clockwise: false)
//画小圆
let path3_1 = UIBezierPath()
path3_1.addArc(withCenter: CGPoint(x: width / 2, y: width / 2), radius: r * 2, startAngle: .pi, endAngle: .pi * 2, clockwise: false)
path3.append(path3_1)
//回到原处
path3.addLine(to: ball3.center)
//执行动画
let animation3 = CAKeyframeAnimation(keyPath: "position")
animation3.path = path3.cgPath
animation3.repeatCount = MAXFLOAT
animation3.isRemovedOnCompletion = false
animation3.duration = 1.6
animation3.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
ball3.layer.add(animation3, forKey: "animation3")
// 放大缩小动画
let scaleAnimation = createBasicAnimation(withKeyPath: "transform.scale")
scaleAnimation.fromValue = 1.0
scaleAnimation.toValue = 1.3
scaleAnimation.duration = 1.6/2
scaleAnimation.isRemovedOnCompletion = false
scaleAnimation.repeatCount = MAXFLOAT
scaleAnimation.autoreverses = true
scaleAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
ball1.layer.add(scaleAnimation, forKey: "scale")
ball2.layer.add(scaleAnimation, forKey: "scale")
ball3.layer.add(scaleAnimation, forKey: "scale")
}
}
调用
let view = MGSquaresAnimationView(animationViewType: .Square(animationLayerTintColor: UIColor.red, squareSize: 60))
// let view = MGSquaresAnimationView(animationViewType: .Circle(ballWidth: 30))
self.view.addSubview(view)
view.startAnimating()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
view.stopAnimating()
view.removeFromSuperview()
}