Search code examples
objective-ccore-animation

How to add an animated layer at a specific index


I am adding two CAText layers to a view and animating one of them. I want to animate one layer above the other but it doesn't get positioned correctly in the layer hierarchy until the animation has finished. Can anyone see what I have done wrong? The animation works, it is just running behind 'topcharlayer2' until the animation has finished.

- (CABasicAnimation *)topCharFlap
{
CABasicAnimation *flipAnimation;


flipAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; 
flipAnimation.toValue      = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(1.57f, 1, 0, 0)];
flipAnimation.fromValue    = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0, 1, 0, 0)]; 
flipAnimation.autoreverses = NO; 
flipAnimation.duration     = 0.5f;
flipAnimation.repeatCount  = 10;


return flipAnimation;
}

- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
    [self setBackgroundColor:[UIColor clearColor]]; //makes this view transparent other than what is drawn.

    [self initChar];
}

return self;
}

static CATransform3D CATransform3DMakePerspective(CGFloat z)
{
CATransform3D t = CATransform3DIdentity;
t.m34 = - 1. / z;
return t;
}



-(void) initChar 
{
UIFont *theFont = [UIFont fontWithName:@"AmericanTypewriter" size:FONT_SIZE];

self.layer.sublayerTransform = CATransform3DMakePerspective(-1000.0f);

topHalfCharLayer2 = [CATextLayer layer];

topHalfCharLayer2.bounds = CGRectMake(0.0f, 0.0f, CHARACTERS_WIDTH, 100.0f);
topHalfCharLayer2.string = @"R";    
topHalfCharLayer2.font = theFont.fontName;
topHalfCharLayer2.fontSize = FONT_SIZE;
topHalfCharLayer2.backgroundColor = [UIColor blackColor].CGColor;
topHalfCharLayer2.position = CGPointMake(CGRectGetMidX(self.bounds),CGRectGetMidY(self.bounds));

topHalfCharLayer2.wrapped = NO;


topHalfCharLayer1 = [CATextLayer layer];


topHalfCharLayer1.bounds = CGRectMake(0.0f, 0.0f, CHARACTERS_WIDTH, 100.0f);
topHalfCharLayer1.string = @"T";


topHalfCharLayer1.font = theFont.fontName;
topHalfCharLayer1.fontSize = FONT_SIZE;

topHalfCharLayer1.backgroundColor = [UIColor redColor].CGColor;
topHalfCharLayer1.position = CGPointMake(CGRectGetMidX(self.bounds),CGRectGetMidY(self.bounds));
topHalfCharLayer1.wrapped = NO;
//topHalfCharLayer1.zPosition = 100;

[topHalfCharLayer1 setAnchorPoint:CGPointMake(0.5f,1.0f)];

[[self layer] addSublayer:topHalfCharLayer1 ];
[[self layer] insertSublayer:topHalfCharLayer2 atIndex:0];

[topHalfCharLayer1 addAnimation:[self topCharFlap] forKey:@"anythingILikeApparently"];

}

The View which contains this code is loaded by a view controller in loadView. The initChar method is called in the view's initWithFrame method. The target is iOS4. I'm not using setWantsLayer as I've read that UIView in iOS is automatically layer backed and doesn't require this.


Solution

  • From the quartz-dev apple mailing list:

    Generally in a 2D case, addSublayer will draw the new layer above the previous. However, I believe this implementation mechanism is independent of zPosition and probably just uses something like painter's algorithm. But the moment you add zPositions and 3D, I don't think you can solely rely on layer ordering. But I am actually unclear if Apple guarantees anything in the case where you have not set zPositions on your layers but have a 3D transform matrix set.

    So, it seems I have to set the zPosition explicitly when applying 3D transforms to layers.