Issue #566
Code
Create a container that has blur effect
public class HUDContainer: UIVisualEffectView, AnimationAware {
private let innerContentView: UIView & AnimationAware
public let label = UILabel()
public var text: String? {
didSet {
label.text = text
label.sizeToFit()
label.isHidden = text == nil
}
}
public init(contentView: UIView & AnimationAware) {
self.innerContentView = contentView
super.init(effect: UIBlurEffect(style: .light))
self.contentView.addSubview(innerContentView)
self.contentView.addSubview(label)
innerContentView.pinEdgesToSuperview()
configure()
}
public required init?(coder aDecoder: NSCoder) {
fatalError()
}
public func configure() {
layer.cornerRadius = 8
layer.masksToBounds = true
label.isHidden = false
label.font = UIFont.preferredFont(forTextStyle: .body)
label.textColor = UIColor.black
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
label.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 10),
label.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -10),
])
}
public func startAnimation() {
innerContentView.startAnimation()
}
public func endAnimation() {
innerContentView.stopAnimation()
}
}
Make error view with 2 cross lines
import UIKit
public class ErrorView: UIView, AnimationAware {
public let line1 = CAShapeLayer()
public let line2 = CAShapeLayer()
public let animation1 = CASpringAnimation(keyPath: #keyPath(CALayer.transform))
public let animation2 = CASpringAnimation(keyPath: #keyPath(CALayer.transform))
public var lineColor: UIColor = UIColor.darkGray
public var duration: TimeInterval = 0.75
public override init(frame: CGRect) {
super.init(frame: frame)
layer.addSublayer(line1)
layer.addSublayer(line2)
configure()
}
public required init?(coder aDecoder: NSCoder) {
fatalError()
}
public override func layoutSubviews() {
super.layoutSubviews()
configureSize()
}
public func configure() {
[line1, line2].forEach {
$0.backgroundColor = lineColor.cgColor
}
[animation1, animation2].forEach {
$0.fromValue = 0
$0.damping = 0.33
$0.initialVelocity = 0.01
$0.mass = 0.2
$0.duration = duration
$0.valueFunction = CAValueFunction(name: CAValueFunctionName.rotateZ)
$0.timingFunction = CAMediaTimingFunction(name: .easeIn)
}
animation1.toValue = CGFloat.pi / 4
animation2.toValue = -CGFloat.pi / 4
}
private func configureSize() {
guard line1.frame.width <= 0 else {
return
}
[line1, line2].forEach {
$0.cornerRadius = 3
$0.frame.size = CGSize(width: bounds.width*0.6, height: 6)
$0.position = layer.position
}
}
public override func didMoveToWindow() {
super.didMoveToWindow()
line1.transform = CATransform3DIdentity
line2.transform = CATransform3DIdentity
}
public func startAnimation() {
line1.transform = CATransform3DMakeRotation(CGFloat.pi/4, 0, 0, 1.0)
line2.transform = CATransform3DMakeRotation(-CGFloat.pi/4, 0, 0, 1.0)
line1.add(animation1, forKey: nil)
line2.add(animation2, forKey: nil)
}
public func stopAnimation() {
line1.removeAllAnimations()
line2.removeAllAnimations()
}
}
Make loading progress using replicator layers
import UIKit
public class ProgressView: UIView, AnimationAware {
public let replicatorLayer = CAReplicatorLayer()
public let animation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))
public let line = CALayer()
public var lineCount: Int = 12
public var duration: TimeInterval = 1.0
public var lineSize: CGSize = CGSize(width: 20, height: 6)
public var lineColor: UIColor = UIColor.darkGray
public override init(frame: CGRect) {
super.init(frame: .zero)
configure()
}
public required init?(coder aDecoder: NSCoder) {
fatalError()
}
public func configure() {
let angle = CGFloat.pi * 2 / CGFloat(lineCount)
let rotation = CATransform3DMakeRotation(angle, 0, 0, 1.0)
replicatorLayer.instanceTransform = rotation
replicatorLayer.instanceCount = lineCount
replicatorLayer.instanceDelay = duration / TimeInterval(lineCount)
line.backgroundColor = lineColor.cgColor
line.frame.size = lineSize
line.cornerRadius = lineSize.height / 2
animation.fromValue = 1.0
animation.toValue = 0.0
animation.repeatCount = Float.greatestFiniteMagnitude
animation.timingFunction = CAMediaTimingFunction(name: .linear)
animation.duration = duration
replicatorLayer.addSublayer(line)
layer.addSublayer(replicatorLayer)
// x: the larger, the closer to center
// y: half the height, changing affects rotation of lines
line.position = CGPoint(x: 48, y: 75)
}
public override func layoutSubviews() {
super.layoutSubviews()
replicatorLayer.frame = bounds
}
public func startAnimation() {
line.add(animation, forKey: nil)
}
public func stopAnimation() {
line.removeAllAnimations()
}
}
Make success view with check mark animation
import UIKit
public class SuccessView: UIView, AnimationAware {
public let shapeLayer = CAShapeLayer()
public let animation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeEnd))
public var lineColor: UIColor = UIColor.darkGray
public var duration: TimeInterval = 0.25
public override init(frame: CGRect) {
super.init(frame: frame)
layer.addSublayer(shapeLayer)
configure()
}
public required init?(coder aDecoder: NSCoder) {
fatalError()
}
public override func layoutSubviews() {
super.layoutSubviews()
configurePath()
}
public func configure() {
shapeLayer.lineCap = .round
shapeLayer.lineJoin = .round
shapeLayer.fillColor = nil
shapeLayer.strokeColor = lineColor.cgColor
shapeLayer.lineWidth = 6
animation.timingFunction = CAMediaTimingFunction(name: .easeIn)
animation.fromValue = 0.0
animation.toValue = 1.0
animation.duration = duration
}
private func configurePath() {
let size = CGSize(width: 80, height: 60)
shapeLayer.frame = CGRect(origin: .zero, size: size)
shapeLayer.position = layer.position
let path = UIBezierPath()
path.move(to: CGPoint(x: size.width * 0, y: size.height * 0.48))
path.addLine(to: CGPoint(x: size.width * 0.38, y: size.height))
path.addLine(to: CGPoint(x: size.width, y: size.height * 0.01))
shapeLayer.path = path.cgPath
}
public override func didMoveToWindow() {
super.didMoveToWindow()
shapeLayer.strokeEnd = 0.0
}
public func startAnimation() {
shapeLayer.strokeEnd = 1.0
shapeLayer.add(animation, forKey: nil)
}
public func stopAnimation() {
shapeLayer.removeAllAnimations()
}
}