开发者

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 la开发者_如何学运维yer:

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


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"];
}


Have you tried adding a [self.view bringSubviewToFront:imageA]; in your animation sequence?


You could try to translate on the z axis and bring A forward first. Perform the rotation and then set the z back to its starting value.

Also, you probably won't see any perspective on the rotation unless you set the .m34 property on the transform. Try something like this:

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -300.0f;
transform = CATransform3DRotate(transform, 0.0f, M_PI, 0.0f);

CABasicAnimation *rotateAnimation = [CABasicAnimation 
                                          animationWithKeyPath:@"transform"];
rotateAnimation.fromValue = [NSValue 
                                 valueWithCATransform3D(CATransformIdentity)];
rotateAnimation.toValue = [NSValue valueWithCATransform3D(transform)];
rotateAnimation.duration = 5.0;

[imageA.layer addAnimation:rotateAnimation forKey:@"rotate"];

You transaction block is unnecessary.

Best Regards.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜