Sign component of `fromValue` / `toValue` ignored when animating `transform.scale.x` and `transform.scale.y` simultaneously

Number:rdar://FB9862872 Date Originated:2022-1-28
Status:Closed Resolved:Yes
Product:Core Animation API Product Version:
Classification:Incorrect/Unexpected Behavior Reproducible:yes
When using `CABasicAnimation` to animate `transform.scale.x` and `transform.scale.y` simultaneously, the resulting animation is different from performing a single animation on `transform`. Specifically, the sign component of `fromValue` / `toValue` is ignored.

With a simple CALayer:

let textLayer = CATextLayer()
textLayer.string = "Hello world"
textLayer.foregroundColor = UIColor.white.cgColor
textLayer.backgroundColor =
textLayer.position = CGPoint(x: 200, y: 300)
textLayer.bounds.size = CGSize(width: 200, height: 200)

these two equivalent CAAnimation configurations result in different animations at runtime:

(1) animateSeparately

let scaleX = CABasicAnimation(keyPath: "transform.scale.x")
scaleX.duration = 1.0
scaleX.fromValue = -0.5
scaleX.toValue = -1
scaleX.repeatCount = .greatestFiniteMagnitude
scaleX.autoreverses = true
textLayer.add(scaleX, forKey: "transform.scale.x")

let scaleY = CABasicAnimation(keyPath: "transform.scale.y")
scaleY.duration = 1.0
scaleY.fromValue = -0.5 // results in same animation as `scaleY.fromValue = 0.5`
scaleY.toValue = -1 // results in same animation as `scaleY.toValue = 1`
scaleY.repeatCount = .greatestFiniteMagnitude
scaleY.autoreverses = true
textLayer.add(scaleY, forKey: "transform.scale.y")

(2) singleAnimation

let transform = CABasicAnimation(keyPath: "transform")
transform.duration = 1.0
transform.fromValue = CATransform3DMakeScale(-0.5, -0.5, 1)
transform.toValue = CATransform3DMakeScale(-1, -1, 1)
transform.repeatCount = .greatestFiniteMagnitude
transform.autoreverses = true
textLayer.add(transform, forKey: "transform")

I expect these two CAAnimation configurations to result in the same animation at runtime, where the layer is flipped across both the x axis and y axis.



Thanks for submitting this report. This behaves as expected.

There is inherent ambiguity in a transform matrix. For example, Scale(-0.5, -1, -1) * Rotation(PI, 1, 0, 0) is the same transform matrix as Scale(-0.5, 1, 1).

If scale.y is then set to -0.5, you would not get a y-flip in the first decomposition, and that’s the “issue” you observed. There’s no “fix” for this because whichever way we decide to decompose a transform matrix for merging multiple animations, one can always find a counterexample due to the ambiguity.

By cal.stephens at Feb. 28, 2022, 6:44 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!