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

Animate CAShapeLayer path from old value to new value in Swift

我是 Core Animation 的新手,我正在尝试根据新数据将 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 的 Core Animation 文档,并在此处的堆栈溢出中寻找可能的线索,但到目前为止还没有任何运气。

据我所知,通过在动画中只分配一个值,核心动画会自己找出路径,但到目前为止还没有成功。我还尝试计算新旧最高 Y 值之间的差异,并使用 byValue,有无 fromValuetoValue

绘制了更新的路径,但遗憾的是 strokeEnd更新后没有显示动画。

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

干杯!


编辑以根据@matt 的反馈添加更多详细信息:TLDR;更新路径,我想我应该用 toValue 制作动画。

我正在存储一个数组,其中包含 CAShapeLayer 之后的 UIBezierPath。路径是根据可以是三个不同值的数据确定的,应该从 (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 首先设置为旧列,然后创建新路径,我可以使用 [= 为路径设置动画13=] 对于路径,使用来自值的动画作为旧路径,并将 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! :)