CATransaction rotate layer 360 degree strange

2019-01-29 09:02发布

问题:

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?

回答1:

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 of M_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.