Animate custom CALayer properties inside a CATransaction
Asked Answered
G

2

8

Until now I've been able to animate the custom properties of my CALayer subclass, thanks to + (BOOL)needsDisplayForKey:(NSString *)key and CABasicAnimations.

However it turns out that chaining animations can become very tricky because all the code takes place in a single animationDidStop:finished: method.

So I wanted to switch to CATransactions since they support the new block syntax, which would allow me to specify a completion block with + (void)setCompletionBlock:(void (^)(void))block.

But it appears to me that CATransaction can only animate the so-called 'animatable properties' and it doesn't work with my custom layer properties, even with the needsDisplayForKey: method implemented.

So is there a way to make custom properties in a CALayer to animate with CATransaction?

EDIT: My intent is to do something along the lines:

[CATransaction begin];
[CATransaction setAnimationDuration:0.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[CATransaction setCompletionBlock:^{
    NSLog(@"blabla");
}];

myLayer.myProperty = newValue;

[CATransaction commit];

The update of myProperty value to newValue is not animated. I've tried to implement actionForLayer:forKey: in the view managing myLayer to return a CABasicAnimation. But actionForLayer:forKey: is never called with the key myProperty. And yes, myLayer is not view.layer but a sublayer, and yes I set the delegate of myLayer to the containing view.

Gold answered 8/11, 2010 at 8:49 Comment(0)
H
10

I believe, based on my reading of some source code, that you can still use a CABasicAnimation within the CATransaction. Any CAAnimations added between the [CATransaction begin] and [CATransaction commit] should be a part of the transaction.

[CATransaction begin];
[CATransaction setAnimationDuration:0.5];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[CATransaction setCompletionBlock:^{
    NSLog(@"blabla");
}];

// Create the CABasicAnimation using your existing code
CABasicAnimation *myPropertyAnim = [CABasicAnimation animationWithKeyPath:@"myProperty"];
// TODO: Setup animation range
myPropertyAnim.toValue = newValue;

// The CATransaction does not observe arbitrary properties so this fails:
//myLayer.myProperty = newValue;

// Add the CAAnimation subclass during the CATransaction
[myLayer addAnimation:myPropertyAnim forKey:@"myKey"];

[CATransaction commit];

Apologies that I don't have a project setup to easily test this now, but I believe it will work.

Check these site for the code:

Code that I referenced:

[CATransaction begin];
[topLayer addAnimation:topAnimation forKey:@"flip"];
[bottomLayer addAnimation:bottomAnimation forKey:@"flip"];
[CATransaction commit];
Hatter answered 9/11, 2010 at 14:7 Comment(1)
I confirm that it works however I feel a bit disappointed that it's not possible to have the same magic behind custom properties than the animatable properties. And I'm going to run some tests to see what happens if the duration of the CATransaction is set to a lower value than any of the ones of the enclosed CAAnimationsGold
E
1

There's a great class called CAAnimationBlocks, and explained here, that is a category on CAAnimation that allows you to use completion blocks like you would on a UIView.

You use it simply by calling:

CABasicAnimation myAnimation;
[myAnimation setCompletion:^(BOOL finished) { // Do something }];
Extirpate answered 22/12, 2011 at 16:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.