views:

110

answers:

2

Hi,

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.

A: 

A couple thoughts come to mind:

  • Try adding the 'R' layer to the layer hierarchy before you start the animation.

  • Instead of inserting the 'T' layer at index 1, use [[self layer] addSublayer: topHalfCharLayer1]; to add it and then do the insert for the 'R' layer with [[self layer] insertSublayer:topHalfCharLayer2 atIndex:0];

  • Have you tried to play with the layer zPosition? This determines the visual appearance of the layers. It doesn't actually shift the layer order, but will change the way they display--e.g. which layers is in front of/behind which.

  • I would also suggest you remove the animation code until you get the layer view order sorted. Once you've done that, the animation should just work.

If you have further issues, let me know in the comments.

Best regards.

Matt Long
Hi - thanks for your reply! I've edited the code above. No matter when / where I insert the layer it doesn't seem to make a difference. zPosition DOES make a difference but if I set a high value, the layer shrinks due to the perspective I have set. If I remove the animation, the layer hierarchy is correct.
codecowboy
Somebody else mentioned that one shouldn't Mix CALayers with UIViews. Is that what I am doing? Is a UIView's layer property in some way *special*?
codecowboy
UIView's all have a backing layer. It *is* a CALayer, so saying that you shouldn't mix CALayer and UIViews is nonsense. You can't use a CALayer without a UIView. The *layer* property is special in that it is the root layer of the view. It has some special characteristics, but for most things it works the same as any other layer.What does your CATransform3DMakePerspective method look like? Are you performing a translate or just a scale?
Matt Long
Thanks again - I have added the other methods above.
codecowboy
Can't you just set a zposition that's smaller by a really small amount, so that it doesn't affect your perspective transform much? Since regular `CALayer``s are basically a 2D affair when it comes to composition, you wouldn't have to be afraid of a layer with a 3D transform "sticking through" another layer or anything.
ig2r
Maybe we should back up a little here and figure out what affect you're going for. I plugged your code into a project to see what results I get and I can duplicate the problem exactly. I just wonder if what you're trying to get it to do may have a simpler solution. Is there somewhere you've seen the affect you're going for that I can view to get a better idea?
Matt Long
I want an effect similar to a flip clock as described here:http://www.voyce.com/index.php/2010/04/10/creating-an-ipad-flip-clock-with-core-animation/ (I found this after I started)
codecowboy
A: 

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.

codecowboy