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上一篇: 使用通用网络摄像头进行对象检测