1

I'm having a lot of trouble exporting a video with animated layers.

The final goal is to export to a video (that's why I need this done with CALayers) a moving CAShapeLayer around the screen and a line following its trace.

First of all, I have an array of CGPoint with all the coordinate points which a CAShapeLayer should use to animate itself. To create the animation I'm using a CAKeyframeAnimation.

let values = [CGPoint(x: 50, y: 100), 
              CGPoint(x: 100, y: 150)] //Example values

let animation = CAKeyframeAnimation()
animation.keyPath = "position"
animation.values = values
animation.duration = videoLength

With this, I'm able to show the CALayer moving around the screen. It's 1 value per frame of the video, it's a 1:1 value.

The real problem comes with adding a line that shows the path of the CAShapeLayer.

What I think I might do, is to create lines with UIBezierPath, animate them and add each line

lines.forEach { (line) in
    let path = UIBezierPath()
    let shapeLayer = CAShapeLayer()
    for (index, point) in line.points.enumerated() {
        if index == 0 {
            path.move(to: point)
        } else {
            path.addLine(to: point)
        }
    }
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = line.color.cgColor
    shapeLayer.lineWidth = 4
    shapeLayer.position = animatedLayer.position
    shapeLayer.path = path.cgPath
    shapeLayer.opacity = 0

    shapeLayers.append(shapeLayer)
}

And to animate the lines...

var timeOffset: Double = 0
let eachLineTime = totalTime / Double(shapeLayers.count)
for shapeLayer in shapeLayers {
    
    CATransaction.begin()
    
    mainLayer.addSublayer(shapeLayer)
    
    let strokeAnimation = CABasicAnimation(keyPath: "strokeEnd")
    strokeAnimation.fromValue = 0
    strokeAnimation.toValue = 1
    strokeAnimation.duration = eachLineTime
    strokeAnimation.beginTime = CACurrentMediaTime() + timeOffset
    
    let opacityAnimation = CABasicAnimation(keyPath: "opacity")
    opacityAnimation.fromValue = 0
    opacityAnimation.toValue = 1
    opacityAnimation.duration = eachLineTime
    opacityAnimation.beginTime = CACurrentMediaTime() + timeOffset
    
    CATransaction.setCompletionBlock {
        shapeLayer.strokeColor = UIColor.orange.cgColor
        shapeLayer.opacity = 1
    }
    
    shapeLayer.add(strokeAnimation, forKey: nil)
    shapeLayer.add(opacityAnimation, forKey: nil)
    timeOffset += eachLineTime
    CATransaction.commit()
}

I need them to be different lines because I want to change the color of each line when it finishes each animation.

I'm getting the next output in Swift Playgrounds

enter image description here

But I'm not getting anything when I export the video in the app.

How can I simply add a trail of the first CAShapeLayer to see the (square in this case) moving path?

How can I move the CABasicAnimation with the same timing of the CAKeyframeAnimation?

Shayan Shafiq
  • 1,447
  • 5
  • 18
  • 25
tzonGoza
  • 361
  • 3
  • 10

0 Answers0