ACGAffineTransform
是一个 3x3 矩阵,其最右边的列永久设置为 (0, 0, 1) T。所以它实际上存储了六个值,称为a、b、c、d、tx和ty。前四个控制旋转、缩放和倾斜。最后两个控制翻译。
您可能认为从一个变换T
到另一个变换的动画U
是一个简单的组件插值问题:T.a
to U.a
、T.b
toU.b
等(我称之为“简单插值”。)
你会错的。
好的,在这里坚持我。这个解释看起来很迂回,但我保证到最后你会明白为什么零比例会破坏动画。
这是我制作的一个演示应用程序。它只是在恒等变换和 160° 旋转(不是180° )之间进行插值。

请注意两件事:图像先缩小然后扩大,并且它没有均匀的角速度。旋转开始缓慢,加速,然后再次减速。那不是我生涩的手部动作;它确实使用简单的插值来表现这种方式。
那么这里发生了什么?让我们看看中途的变换(80˚):

在文本中:
[0.030153692, 0.17101011, -0.17101011, 0.030153692, 0, 0]
80˚ 的旋转变换应该是什么样的?像这样:
[0.17364822, 0.98480773, -0.98480773, 0.17364822, 0, 0]
您可能已经注意到,这些矩阵完全不同。仅表示旋转的变换有几个属性:a*a + b*b == 1
、a == d
和b == -c
。真正的旋转矩阵具有所有这些属性,但简单插值矩阵没有。具体来说,它a*a + b*b == .030153695
与 1 相差甚远。这意味着它不仅代表旋转,还代表缩放。
这意味着,一般来说,您不能仅在两个变换之间进行插值并获得不错的结果。所以系统做了一些更复杂的事情。
Core Animation 将变换分解为四个部分:旋转角度、比例因子、剪切因子和平移。它对这些部分进行插值,并使用插值来计算动画的中间变换。
“好吧”,你是说,“但这与破坏动画的零尺度矩阵有什么关系?”</p>
您可以在此 mathoverflow Q&A中找到分解矩阵的数学方法。请注意,要计算旋转角度和剪切因子,您需要除以矩阵的至少一个分量(该答案中的A 11或 A 21a
或)。但是,当您按零因子缩放时,这些组件将变为零。你不能除以零。b
CGAffineTransform
因此,当系统尝试分解您的转换时,它会失败并放弃。
我不是说这是好的行为,但这是我们生活的行为。