Search code examples
iosswiftcalayercaanimation

Dots following the path


I am looking for some simple method that will animate dots moving by closed path.

I have some path created with UIBezierPath. Which is represented by CAShapeLayer.

I want to place on this shape dots that will move around this closed path. The problem is that I couldn't find the best method. I do not want to add every dot programmatically. Maybe there is some method where could be use particles.

Path will have different shapes. The most important thing is to please dots with the same distance between each other.

I will be glad for help


Solution

  • Here is an example you can run in playground.

    It's based on an article by Matt Long (from a while back) http://www.cimgf.com/2009/10/20/marching-ants-with-core-animation/

    import UIKit
    import PlaygroundSupport
    
    let container = UIView(frame: CGRect(x: 0, y: 0, width: 600, height: 700))
    
    container.backgroundColor = UIColor.green
    
    let v = UIView(frame: CGRect(x: 100, y: 100, width: 300, height: 300))
    v.backgroundColor = UIColor.yellow
    
    let shp = CAShapeLayer()
    shp.bounds = v.bounds
    let pth = UIBezierPath()
    pth.move(to: CGPoint(x: 20, y: 220))
    pth.addLine(to: CGPoint(x: 20, y: 40))
    pth.addLine(to: CGPoint(x: 40, y: 80))
    pth.addLine(to: CGPoint(x: 120, y: 40))
    pth.addLine(to: CGPoint(x: 140, y: 40))
    pth.close()
    shp.strokeColor = UIColor.orange.cgColor
    shp.fillColor = UIColor.cyan.cgColor
    shp.lineWidth = 3.0
    
    shp.lineDashPattern = [5, 5]
    
    shp.path = pth.cgPath
    shp.position = CGPoint(x: 150, y: 150)
    v.layer.addSublayer(shp)
    
    container.addSubview(v)
    
    let dashAnim = CABasicAnimation(keyPath: "lineDashPhase")
    dashAnim.fromValue = 0
    dashAnim.toValue = 15
    dashAnim.duration = 0.75
    dashAnim.repeatCount = 10000
    
    shp.add(dashAnim, forKey: "lineDashPhase")
    
    PlaygroundPage.current.liveView = container
    PlaygroundPage.current.needsIndefiniteExecution = true