我如何创建一个 iOS CAAnimation 并自己定义每个插值?

How can I create an iOS CAAnimation and define every interpolated value myself?

我想为 CAShapeLayer 的路径设置动画。但是,此路径是使用许多弧创建的。弧的数量在路径的开始和结束值中是相同的。然而,由于弧的长度不同,这似乎意味着实际路径使用不同数量的贝塞尔曲线控制点。这意味着动画是不可预测的,而且非常不稳定*。

到目前为止,我的解决方案是创建一个 CAKeyFrameAnimation,并放入大量关键帧。它仅适用于每秒非常多的关键帧。 (大约 200 到 300)。再低一点,就会出现故障*。

这种方法非常粗糙,因为它的成功取决于实际设备上的实际帧速率,并创建比动画实际需要更多的关键帧实例,从而浪费内存。 所以我的问题是:有没有办法创建一个动画,我必须以某种方式创建每个值?我正在想象一些基于委托的方法,在这种方法中,系统会根据关键时间向我询问一个值。我不知道解决我的问题的最佳方法是什么。

*注意:我所说的故障是仅在一帧内出现的看起来很奇怪的路径。

您应该尝试使用 CADisplayLink

这是一个例子:

func setupAnimation() {
    let dispLink = CADisplayLink(target: self, selector: #selector(updateAnimation))
    dispLink.preferredFramesPerSecond = 60 //will update 60 times per second (the default for iOS devices) ... this line of code is optional depending on the fps you want for your animation
    dispLink.add(to: RunLoop.current, forMode: RunLoop.Mode.common)
}

func updateAnimation() {
    //do your animation code here
}

使用显示器 link 会使你的动画 link 达到屏幕的刷新率,这样它就很流畅,你基本上可以做任何你想做的事情而不会显得断断续续

UIBezierPath,它是基础核心基础 class,CGPath,在根据弧的角度创建弧时确实使用可变数量的控制点。

因此,正如您所发现的,如果您尝试为包含不同角度的弧的路径制作动画,随着路径中控制点数量的变化,您会得到非常奇怪的绘图伪像。

我建议改用 Catmull-Rom 样条曲线来创建圆弧。 Catmull-Rom 样条是一种不同类型的三次曲线,其中所有控制点都在曲线上。我从 Erica Sadun 的优秀 iOS 开发者食谱系列中了解了 Catmull-Rom 样条(强烈推荐阅读。)

如果您创建一个 Catmull-Rom 样条,其中大约 10 个点均匀分布在一个圆周围,您得到的结果曲线将非常接近一个圆。 (我最初推荐 8 个控制点,但我只是试了一下,描述一个完整圆的曲线看起来并不完美,直到你有至少 10 个控制点。)如果你想生成一个 CGPath 包含一个圆弧较小的角度,生成 10 个控制点,覆盖或多或少的弧线。

我在 Github 上有一个名为 TrochoidDemo 的项目,它使用 Catmull Rom Splines 来创建逼真的水波。你可以忽略其中的大部分内容,但它包含一个文件 SmoothCGPointsArray.swift,它将采用一个控制点数组并使用 Catmull-Rom 样条 return 一个新数组,中间点描述了你的之间的平滑曲线控制点。

你想要的那个文件中的函数是smoothPointsInArray(_:granularity:adjustGranularity:)

adjustGranularity参数默认为true。该参数告诉函数根据控制点之间的距离改变它创建的平滑点的数量。您需要覆盖默认值并使用 adjustGranularity=false 调用该函数,因为对于动画您总是需要相同数量的点。

您只需使用一个控制点数组调用该函数,其中包含 10 个点,用于您要绘制的每个圆弧,无论角度如何。它将 return 一个 CGPoints 数组,然后您将使用 GCPoints 的结果数组使用 lineTo() 命令生成一个 UIBezierPath,然后从您的 UIBezierPath到你的动画。

在您的源点数组中,如果您希望给定点成为尖角,请连续两次添加该点。如果需要线段,请将线段的两个端点相加两次。

圆的 8 点近似值如下所示:

这是圆的 10 点近似值:

(在上面的每个图像中,Catmull-Rom 近似以黑色绘制,控制点以蓝色显示,其中 Cocoa 绘制的圆圈以蓝色绘制。请注意 Cocoa使用贝塞尔曲线创建它的圆,所以 Cocoa 圆也是近似值。)