I want to perform an infinite 360 degrees rotation animation, so I coded:
- (void)rotate
{
__weak typeof(self) weakSelf = self;
[CATransaction begin];
[CATransaction setDisableActions:NO];
[CATransaction setCompletionBlock:^{
[weakSelf rotate];
}];
[CATransaction setAnimationDuration:1.0];
[CATransaction setAnimationTimingFunction:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
self.squareLayer.transform = CATransform3DRotate(self.squareLayer.transform, M_PI, 0, 0, 1);
[CATransaction commit];
}
M_PI means 180 degrees, so I believe the layer can be rotated from 0
to M_PI * 1
, M_PI * 2
...
But it turns out to be an rotation from 0
to M_PI
, then M_PI
to 0
.
I can make it through a CABasicAnimation
:
CABasicAnimation *animatin = [CABasicAnimation animationWithKeyPath:@"transform"];
animatin.duration = 1.0;
animatin.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0, 0, 1)];
animatin.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)];
animatin.repeatCount = HUGE_VALF;
animatin.fillMode = kCAFillModeForwards;
[self.squareLayer addAnimation:animatin forKey:@"a"];
Codes above rotate the layer 360 degrees perfectly.
But I am really confused about the first implementation, why it rotates so strange?
It's an edge case. With implicit animation, you are not able to say "rotate clockwise this amount". You are merely saying "set the transform to this value, and animate that effect." Well, how should that change be animated? The runtime has to make up an answer, and it isn't obvious how to do that. A transform of rotation by M_PI is the same "distance" in both directions, so the answer it makes up is arbitrary. You can see the problem even more clearly if you supply a value of
M_PI+0.1
vs. a value ofM_PI-0.1
; you actually get reverse results: one keeps turning clockwise, the other keeps turning counterclockwise.With CABasicAnimation, on the other hand, you have a from-value (implicit or explicit) and a to-value, so you are able to express the notion "increase" (i.e. a positive difference means turn clockwise). It's even clearer if you animate by setting just the
byValue
.