Continuous animation along path

Hi, please could You help me, how to do continuous (infinity) line animation along path without stopping - see attached picture

— for path:

path = UIBezierPath(roundedRect: CGRect.init(x: 0, y: 0, width: 100, height: 100), byRoundingCorners:.allCorners, cornerRadii: CGSize(width:16, height:16))

— animations:

let strokeEndAnimation: CAAnimation = {

        let animation = CABasicAnimation(keyPath: "strokeEnd")

        animation.fromValue = 0

        animation.toValue = 1

        animation.duration = 10

        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        

        let group = CAAnimationGroup()

        group.duration = 12

        group.repeatCount = MAXFLOAT

        group.animations = [animation]

        return group

    }()

    

    let strokeStartAnimation: CAAnimation = {

        let animation = CABasicAnimation(keyPath: "strokeStart")

        animation.beginTime = 2

        animation.fromValue = 0

        animation.toValue = 1

        animation.duration = 10

        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        

        let group = CAAnimationGroup()

        group.duration = 12

        group.repeatCount = MAXFLOAT

        group.animations = [animation]

        

        return group
![continuous animation
    }()

continuous animation

Thank You
Martin

Hi @martinzly,
you have the correct idea when you are using the repeatCount property, however have you tried using the .infinity value instead of MAXFLOAT?

cheers,

Jayant

Hi @jayantvarma, I don’t have problem how to set infinity animation. I have problem, that the animation doesnt look good, because in each loop - the line stop and start, but I need continuous animation without break.
Thank You

@hi martinzly,
One small observation, you have a total duration of 12, where you are stopping the animation with 2 second delay, try to not have that and maybe you will have a smooth continuous animation.

cheers,

Jayant

This don’t help me, I need line (length of line < total length of rectangle) animation along rectangle, that mean small line (snake), which go along rectangle continuously. Thank You

The line have to have same length in each time.

Hi @martinzly,
could you provide the project file with the animation to have a look at.

cheers,

Jayant

Hi @martinzly,
A couple of things, you will require two stroke animations, the startstroke and the endstroke. With the endStroke animation following a couple of miliseconds after. So what it will do is display the stroke and also start to erase the same.

Given the time that I can put into this, once it finishes, the stroke is complete, in theory, you will have to have another animation that fills the gap and starts again.

Here’s some code to get you started,

func animate() {
    //call this from viewDidLoad()
    
    let centerRectInRect = {(rect: CGRect, bounds: CGRect) -> CGRect in
        return CGRect(x: bounds.origin.x + ((bounds.width - rect.width) / 2.0),
                      y: bounds.origin.y + ((bounds.height - rect.height) / 2.0),
                      width: rect.width,
                      height: rect.height)
    }
    
    
    let shapeLayer = CAShapeLayer()
    shapeLayer.frame = centerRectInRect(CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0), self.view.bounds)
    self.view.layer.addSublayer(shapeLayer)
    
    
    shapeLayer.strokeStart = 0.0
    shapeLayer.strokeEnd = 1.0
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.red.cgColor
    shapeLayer.lineWidth = 3.0
    
    let rect = shapeLayer.bounds
    let path = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: 16, height: 16))
    shapeLayer.path = path.cgPath

    let strokeStartAnim = CAKeyframeAnimation(keyPath: "strokeStart")
    strokeStartAnim.values = [1, 0]
    strokeStartAnim.keyTimes = [0,1]
    strokeStartAnim.duration = 2.0
    //strokeStartAnim.repeatCount = .infinity
    
    let strokeEndAnim = CAKeyframeAnimation(keyPath: "strokeEnd")
    strokeEndAnim.values = [1, 0]
    strokeEndAnim.keyTimes = [0,1]
    strokeEndAnim.duration = 1.96
    strokeEndAnim.beginTime = 0.373
    //strokeEndAnim.repeatCount = .infinity

    let groupAnim = CAAnimationGroup()
    groupAnim.animations = [strokeStartAnim, strokeEndAnim]
    groupAnim.isRemovedOnCompletion = false
    groupAnim.fillMode = kCAFillModeForwards
    groupAnim.duration = 3.0
    shapeLayer.add(groupAnim, forKey: "AnimateSnake")
    
}

}

Cheers,

Jayant

Sorry, but I don’t want the theory, but solution. Please could You send me some solution? thank You

Sorry but we’re not going to code your app for you. Jayant was kind enough to give you a helpful response - it’s up to you to take it from here.

1 Like

I see my comments, and I am sorry, this looks quite confused. Yes, I don’t want to someone else code my app, but if You see, I had strokeEnd and strokeStart animation already in my question. And all what I need is just how to continue in next loop without start stop and without lose my line length.

Here is my whole code, could You please expand to smooth infinity line animation?

import UIKit

class SpinningView: UIView {
    
    let strokeEndAnimation: CAAnimation = {
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = 0.1
        animation.toValue = 1
        animation.duration = 10
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        
        let group = CAAnimationGroup()
        group.duration = 10
        group.repeatCount = MAXFLOAT
        group.animations = [animation]
        group.isRemovedOnCompletion = false;
        return group
    }()
    
    let strokeStartAnimation: CAAnimation = {
        let animation = CABasicAnimation(keyPath: "strokeStart")
        animation.fromValue = 0
        animation.toValue = 0.9
        animation.duration = 10
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        
        let group = CAAnimationGroup()
        group.duration = 10
        group.repeatCount = MAXFLOAT
        group.animations = [animation]
        group.isRemovedOnCompletion = false;
        return group
    }()
    
 
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        runAnimation()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        runAnimation()
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        runAnimation()
    }

    func runAnimation() {
        
        var path = UIBezierPath()
        
        path = UIBezierPath(roundedRect: CGRect.init(x: 20, y: 20, width: 100, height: 100), cornerRadius: 20)

        let layer = CAShapeLayer()
        
        layer.fillColor = nil
        layer.strokeColor = UIColor.green.cgColor
        layer.lineWidth = 3
        
        layer.position = CGPoint(x: 20, y: 20)
        layer.path = path.cgPath
        layer.lineCap = kCALineCapRound
        layer.add(strokeEndAnimation, forKey: "strokeEnd")
        layer.add(strokeStartAnimation, forKey: "strokeStart")
        
        self.layer.addSublayer(layer)
    }
}

This topic was automatically closed after 166 days. New replies are no longer allowed.