Animate CAShapeLayer path from old value to new value in Swift

I'm new to Core Animation, and I'm trying to update the strokeEnd of a CAShapeLayer , from an old value to a new updated value, based on new data.

So basically I have a drawn CAShapeLayer , and updating it's UIBezierPath , and using CABasicAnimation(forKey: "strokeEnd") , to animate the new strokeEnd by doing this:

layerAnimation = CABasicAnimation(keyPath: "strokeEnd")
layerAnimation.toValue = 1
shapeLayer.strokeEnd = 1
layerAnimation.duration = 0.4
shapeLayer.add(layerAnimation, forKey: animation.identifier)

where animation.identifier is an String Enum value which determine which animation should be used.

So far I've been digging deep in the Apple's Core Animation documentation, and here on stack overflow, for a possible clue, but so far without any luck.

As far as I understand it, by only assigning one value in the animation, core animation would figure out the path itself, but so far with no luck. I've also tried to calculate the difference between the old and new top Y value, and use the byValue , with and without fromValue or toValue .

The updated path is drawn, but unfortunately the animation is not shown with the strokeEnd update.

Any help, hints, or advice, would be received with great gratitude.

Cheers!


Edit to add more details based on @matt's feedback: TLDR; updating path, thought I should animate with toValue.

I'm storing an array containing drawn CAShapeLayer that follows a UIBezierPath . The path is determined based on data that can be of three different values, and should go from (x: i, y: 0) -> (x: i, y: n). where x is a fixed position, and y is the end point of the path, in it's given array[i] column.

If there is an update to the data in the i'th position, I re-calculate the UIBezierPath , which is done in newPath(x:y:h:) -> UIBezierPath

        if let previous: CAShapeLayer = previousColumns[i] {
            shapeLayer = previous
            bezierPath = UIBezierPath()
            bezierPath = newPath(x: xPoint(i), y: newY, viewHeight: height)
            shapeLayer.path = bezierPath.cgPath
            animate(shapeLayer: shapeLayer, animation: .updateAnimation)
        } else { draw new CAShapeLayer with UIBezierPath }

The animate(shapeLayer:animation:) contains the code first mentioned, as it was my understanding that before an animation can take place, either a CABasicAnimation or CAKeyFrameAnimation should be added to the given CAShapeLayer .


Okay so after a bit of guidance, @matt made me realise, that it wasn't the strokeEnd that should be updated, but rather the path. So by tweaking my code a bit, I realised that by setting the UIBezierPath of the new column to be drawn, to the old one at first, and then creating the new path, I could animate the path with a CABasicAnimation for the path, by using the animations from value as the old path, and the toValue as the new value.

        if let previous: CAShapeLayer = previousColumns[i], let oldPath: CGPath = previous.path {
            shapeLayer = previous
            bezierPath = UIBezierPath(cgPath: oldPath)
            shapeLayer.path = bezierPath.cgPath
            let newBezierPath = newPath(x: x, y: newY, viewHeight: height)
            animate(shapeLayer: shapeLayer, animation: .updateAnimation, newBezierPath: newBezierPath.cgPath)
        }

And then update the animation block:

        layerAnimation = CABasicAnimation(keyPath: "path")
        layerAnimation.fromValue = shapeLayer.path
        layerAnimation.toValue = newBezierPath
        shapeLayer.path = newBezierPath

Again, I couldn't have figured this out, without @matt's helpful tips, so thank you @matt! :)

链接地址: http://www.djcxy.com/p/39496.html

上一篇: 使用通用网络摄像头进行对象检测

下一篇: 在Swift中将CAShapeLayer路径从旧值移动到新值