In a CALayer subclass I'm working on I have a custom property that I want to animate automatically, that is, assuming the property is called "myProperty", I want the following code:
[myLayer setMyProperty:newValue];
To cause a smooth animation from the current value to "newValue".
Using the approach of overriding actionForKey: and needsDisplayForKey: (see following code) I was able to get it to run very nicely to simply interpolate between the old and and new value.
My problem is that I want to use a slightly different animation duration or path (or whatever) depending on both the current value and the new value of the property and I wasn't able to figure out how to get the new value from within actionForKey:
Thanks in advance
@interface ERAnimatablePropertyLayer : CALayer {
float myProperty;
}
@property (nonatomic, assign) float myProperty;
@end
@implementation ERAnimatablePropertyLayer
@dynamic myProperty;
- (void)drawInContext:(CGContextRef)ctx {
... some custom drawing code based on "myProperty"
}
- (id <CAAction>)actionForKey:(NSString *)key {
if ([key isEqualToString:@"myProperty"]) {
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:key];
theAnimation.fromValue = [[self presentationLayer] valueForKey:key];
... I want to do something special here, depending on both from and to values...
return theAnimation;
}
return [super actionForKey:key];
}
+ (BOOL)needsDisplayForKey:(NSString *)key {
if ([key isEqualToString:@"myProperty"])
return YES;
return [super needsDisplayForKey:key];
}
@end
You need to avoid custom getters and setters for properties you want to animate.
Override the didChangeValueForKey:
method. Use it to set the model value for the property you want to animate.
Don't set the toValue on the action animation.
@interface MyLayer: CALayer
@property ( nonatomic ) NSUInteger state;
@end
-
@implementation MyLayer
@dynamic state;
- (id<CAAction>)actionForKey: (NSString *)key {
if( [key isEqualToString: @"state"] )
{
CABasicAnimation * bgAnimation = [CABasicAnimation animationWithKeyPath: @"backgroundColor"];
bgAnimation.fromValue = [self.presentationLayer backgroundColor];
bgAnimation.duration = 0.4;
return bgAnimation;
}
return [super actionForKey: key];
}
- (void)didChangeValueForKey: (NSString *)key {
if( [key isEqualToString: @"state"] )
{
const NSUInteger state = [self valueForKey: key];
UIColor * newBackgroundColor;
switch (state)
{
case 0:
newBackgroundColor = [UIColor redColor];
break;
case 1:
newBackgroundColor = [UIColor blueColor];
break;
case 2:
newBackgroundColor = [UIColor greenColor];
break;
default:
newBackgroundColor = [UIColor purpleColor];
}
self.backgroundColor = newBackgroundColor.CGColor;
}
[super didChangeValueForKey: key];
}
@end