Reputation: 6903
Here, I am creating a vanishing circular layer animation. My code is following:
import UIKit
class VanishingLoader: UIView {
private let loaderLayer = CAShapeLayer()
private var layerPaths = [UIBezierPath]()
private let animationframeDuration = 0.25
private var lastFrameDuration = 0.0
weak var parentView: UIView?
var parenViewCenter: CGPoint?{
if let frame = parentView?.bounds{
return CGPoint(x: frame.midX, y: frame.midY)
}
return nil
}
let animationGroup = CAAnimationGroup()
required init?(coder: NSCoder) {
super.init(coder: coder)
}
init(onView view: UIView) {
super.init(frame: view.frame)
parentView = view
layerPaths = preparedPathList
if layerPaths.count > 0 {
let path = layerPaths[0]
addVanishingStrokeLayer(path, withStrokeColor: UIColor.systemGreen, andStrokeWidth: nil)
}
}
private func addVanishingStrokeLayer(_ path: UIBezierPath, withStrokeColor strokeColor:UIColor?, andStrokeWidth strokeWidth: CGFloat?){
let initialPath = layerPaths[0].cgPath
loaderLayer.path = initialPath
loaderLayer.fillColor = UIColor.clear.cgColor
if let loaderLayerColor = strokeColor{
loaderLayer.strokeColor = loaderLayerColor.cgColor
}else{
loaderLayer.strokeColor = defaultStrokeColor.cgColor
}
if let lineWidth = strokeWidth{
loaderLayer.lineWidth = lineWidth
}else{
loaderLayer.lineWidth = 5.0
}
loaderLayer.add(vanishingAnimationGroup(), forKey: "vanishingGroupAnimation")
self.layer.addSublayer(loaderLayer)
}
var preparedPathList: [UIBezierPath]{
var pathList = [UIBezierPath]()
var multiplier : CGFloat = 0.3
for _ in 0..<8 {
if let path = getPathForLayer(withMultiplier: multiplier){
pathList.append(path)
multiplier += 0.10
}
}
return pathList
}
private func getPathForLayer(withMultiplier multiplier: CGFloat = 1.0)->UIBezierPath?{
let radius = 5.0
let path = UIBezierPath(arcCenter: .zero , radius: radius, startAngle: 0, endAngle: 4 * CGFloat.pi, clockwise: true)
return path
}
private func prepareForwardAnimationFrame(forPathCount count: Int)->CASpringAnimation{
let initialPath = layerPaths[count]
let finalPath = layerPaths[count + 1]
let pathAnimation = CASpringAnimation(keyPath: "path")
pathAnimation.fromValue = initialPath.cgPath
pathAnimation.toValue = finalPath.cgPath
pathAnimation.initialVelocity = 1
pathAnimation.damping = 5
pathAnimation.beginTime = lastFrameDuration
pathAnimation.duration = animationframeDuration
return pathAnimation
}
private func vanishingAnimationGroup()->CAAnimationGroup{
var animationPaths = [CASpringAnimation]()
for count in 0..<(layerPaths.count - 1){
let anim = prepareForwardAnimationFrame(forPathCount: count)
animationPaths.append(anim)
lastFrameDuration = anim.beginTime + animationframeDuration
}
animationGroup.animations = animationPaths
animationGroup.duration = (Double(animationPaths.count) * animationframeDuration)
animationGroup.repeatCount = .infinity
animationGroup.fillMode = .forwards
animationGroup.isRemovedOnCompletion = false
return animationGroup
}
public func hide(){
self.removeFromSuperview()
}
public func show(){
if let view = parentView{
view.addSubview(self)
}
}
}
From the ViewController, have to add the following two lines to see the effect.
let loader = VanishingLoader(onView: placeHolderImageView)
loader.show()
The problem, I am facing is when the animation sequence finishes, it goes back to the initial path which is the smallest of the seven paths and that gives a sudden jerking effect. Please help me.
Upvotes: -1
Views: 158
Reputation: 535925
First of all, this should be a key frame animation, not a grouped animation. Second, the change from last to first doesn’t animate because you didn’t animate it. Add another key frame that performs the missing animation.
I rewrote your animation as a key frame animation, and so far, I have this, but I don't think it is what you want, so please say more clearly what the intended effect is supposed to be:
Upvotes: 1