在 Swift 中将 CAShapeLayer 路径从旧值动画化为新值



我是核心动画的新手,我正在尝试根据新数据更新CAShapeLayerstrokeEnd,从旧值更新为新的更新值。

所以基本上我有一个绘制CAShapeLayer,并且更新它是UIBezierPath,并使用CABasicAnimation(forKey: "strokeEnd"),通过这样做来动画新strokeEnd

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

其中animation.identifier是确定应使用哪个动画的String Enum值。

到目前为止,我一直在深入挖掘Apple的核心动画文档,以及堆栈溢出,以寻找可能的线索,但到目前为止没有任何运气。

据我了解,通过在动画中只分配一个值,核心动画会找出路径本身,但到目前为止还没有运气。我还尝试计算新旧顶部 Y 值之间的差异,并使用byValue,带或不带fromValuetoValue

绘制了更新的路径,但遗憾的是,动画未随strokeEnd更新一起显示。

任何帮助、提示或建议,都将不胜感激。

干杯!


根据@matt的反馈进行编辑以添加更多详细信息:TLDR;更新路径,认为我应该使用toValue进行动画处理。

我正在存储一个数组,其中包含UIBezierPath后面的绘制CAShapeLayer。路径是根据可以具有三个不同值的数据确定的,并且应该从 (x: i, y: 0) -> (x: i, y: n) 开始。 其中 x 是固定位置,y 是路径的终点,在给定的 array[i] 列中。

如果第 i 个位置的数据有更新,我会重新计算UIBezierPath,这是在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 }

animate(shapeLayer:animation:)包含首先提到的代码,因为我的理解是,在动画发生之前,应将CABasicAnimationCAKeyFrameAnimation添加到给定的CAShapeLayer中。

好的,经过一些指导,@matt让我意识到,应该更新的不是 strokeEnd,而是路径。因此,通过稍微调整我的代码,我意识到,通过将要绘制的新列的UIBezierPath设置为首先设置为旧列,然后创建新路径,我可以使用路径的CABasicAnimation对路径进行动画处理,方法是使用来自值的动画作为旧路径, 并将 toValue 作为新值。

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)
}

然后更新动画块:

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

同样,如果没有@matt的有用提示,我无法弄清楚这一点,所以@matt谢谢你! :)

最新更新