UIBezierPath,它是基础核心基础类CGPath,在根据弧的角度创建弧时确实使用可变数量的控制点。
因此,正如您所发现的,如果您尝试为包含不同角度圆弧的路径设置动画,随着路径中控制点数量的变化,您会得到非常奇怪的绘图伪影。
我建议使用 Catmull-Rom 样条来创建你的弧线。 Catmull-Rom 样条曲线是一种不同类型的三次曲线,其中所有控制点都在曲线上。我从 Erica Sadun 的杰出 iOS Developers' Cookbook 系列中了解了 Catmull-Rom 样条(强烈推荐阅读。)
如果您创建一个 Catmull-Rom 样条曲线,其中大约 10 个点均匀分布在一个圆周围,您得到的曲线将非常接近一个圆。 (我最初推荐了 8 个控制点,但我只是尝试了一下,描述一个完整圆的曲线在至少有 10 个控制点之前看起来并不完美。)如果你想生成一个包含圆弧的 CGPath较小的角度,生成 10 个控制点,覆盖更少或更多的弧。
我在 Github 上有一个名为 TrochoidDemo 的项目,它使用 Catmull Rom Splines 创建逼真的水波。您可以忽略其中的大部分内容,但它包含一个文件 SmoothCGPointsArray.swift,它将获取一个控制点数组并使用 Catmull-Rom 样条线返回一个新数组,其中包含描述控制点之间平滑曲线的中间点。
你想要在那个文件中的函数是smoothPointsInArray(_:granularity:adjustGranularity:)
adjustGranularity 参数默认为 true。该参数告诉函数根据控制点之间的距离来改变它创建的平滑点的数量。您将需要覆盖默认值并使用adjustGranularity=false 调用该函数,因为对于动画,您总是需要相同数量的点。
您只需使用一组控制点调用该函数,其中包括您要绘制的每条弧线的 10 个点,无论角度如何。它将返回一个 CGPoints 数组,然后您将使用生成的 GCPoints 数组使用 lineTo() 命令生成 UIBezierPath,然后将 CGPath 从您的 UIBezierPath 提供给您的动画。
在您的源点数组中,如果您希望给定点成为尖角,请将该点连续添加两次。如果您想要一条线段,请将线段的两个端点添加两次。
这是一个 8 点近似圆的样子:
这是一个 10 点近似圆的样子:
(在上面的每个图像中,Catmull-Rom 近似值以黑色绘制,控制点以蓝色显示,其中 Cocoa 绘制的圆圈以蓝色绘制。注意 Cocoa 使用贝塞尔曲线来创建它的圆圈,所以 Cocoa圆圈也是近似值。)