Search code examples
iphoneobjective-ccore-animation

Why CABasicAnimation will send the layer's view to back and front?


There are two UIViews of similar size. UIView one (A) is originally on top of UIView two (B). When I try to perform a CABasicAnimation transform.rotation.y on A's layer:

CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
CGFloat startValue = 0.0;
CGFloat endValue = M_PI;
rotateAnimation.fromValue = [NSNumber numberWithDouble:startValue];
rotateAnimation.toValue = [NSNumber numberWithDouble:endValue];
rotateAnimation.duration = 5.0;
[CATransaction begin];
[imageA.layer addAnimation:rotateAnimation forKey:@"rotate"];
[CATransaction commit];

During the animation, the animating layer's UIView (A) will be:

  1. sent back (A is suddenly behind B)
  2. rotating ... passed second half of the animation
  3. sent front (A is now on top of B again)

Is there a way to keep A on top of B for the whole animation period? Thanks!

UPDATE: project source is attached: FlipLayer.zip


Solution

  • The problem is a rotation around the Y axis will, in a true 3D compositing system, make layer A intersect with layer B, such that half of layer A should be visible and half should be behind layer B. CoreAnimation does not provide a true 3D compositing system. Instead it attempts to determine which layer is in front of which other layer, and renders it entirely without intersection. In your case, during the first half of the rotation CoreAnimation has decided that layer B is on top of layer A in the 3D space. The simplest solution is probably to set the zPosition of layer A to layer.bounds.size.width (default is 0) for the duration of the animation (or permanently, if it should always be on top).

    If you want to set it only for the duration of the animation, you can add a second animation for the transform.translation.z key path. Here's your -flip method modified to use this:

    - (IBAction)flip:(id)sender {
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
        CGFloat startValue = 0.0;
        CGFloat endValue = M_PI;
        animation.fromValue = [NSNumber numberWithDouble:startValue];
        animation.toValue = [NSNumber numberWithDouble:endValue];
        animation.duration = 5.0;
        [imageOne.layer addAnimation:animation forKey:@"rotate"];
        animation.keyPath = @"transform.translation.z";
        animation.fromValue = [NSNumber numberWithFloat:imageOne.layer.bounds.size.width];
        animation.toValue = animation.fromValue;
        [imageOne.layer addAnimation:animation forKey:@"zPosition"];
    }