views:

29

answers:

2

I have a custom CALayer (say CircleLayer), containing custom properties (radius and tint). The layer renders itself in its drawInContext: method.

- (void)drawInContext:(CGContextRef)ctx {
    NSLog(@"Drawing layer, tint is %@, radius is %@", self.tint, self.radius);

    CGPoint centerPoint = CGPointMake(CGRectGetWidth(self.bounds)/2, CGRectGetHeight(self.bounds)/2);

    CGContextMoveToPoint(ctx, centerPoint.x, centerPoint.y);
    CGContextAddArc(ctx, centerPoint.x, centerPoint.y, [self.radius doubleValue], radians(0), radians(360), 0);
    CGContextClosePath(ctx);

    /* Filling it */
    CGContextSetFillColorWithColor(ctx, self.tint.CGColor);
    CGContextFillPath(ctx); 
}

I want the radius to be animatable so I've implemented

+ (BOOL)needsDisplayForKey:(NSString *)key {
    if ([key isEqualToString:@"radius"]) {
        return YES;
    }
    return [super needsDisplayForKey:key];
}

And the animation is performed like this:

CABasicAnimation *theAnimation=[CABasicAnimation animationWithKeyPath:@"radius"];
theAnimation.duration=2.0;
theAnimation.fromValue=[NSNumber numberWithDouble:100.0];
theAnimation.toValue=[NSNumber numberWithDouble:50.0];
theAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

[circleLayer addAnimation:theAnimation forKey:@"animateRadius"];

circleLayer.radius = [NSNumber numberWithDouble:50.0];

drawInContext: gets called as expected during the animation to redraw the circle, however the tint is set to nil as soon as the animation starts and gets back to its original value when the animation ends.

I've concluded that if I want to animate a custom property and want other properties to keep their value during the animation, I have to animate them too, which I find not being convenient at all.

The purpose is not to grow/shrink a circle, I know I can use transformation for this. It is only to illustrate with a simple example the problem of animating a single custom property without having to animate all the other ones.

I've made a simple project illustrating the issue, which you can find here: Sample project illustrating the issue

There is probably something I didn't get on how CoreAnimation works, I've performed intensive searching but I'm stuck with no clue. Anyone knows?

A: 
+ (BOOL)needsDisplayForKey:(NSString *)key {
    if ([key isEqualToString:@"radius"] || [key isEqualToString:@"tint"]) {
        return YES;
    }
    return [super needsDisplayForKey:key];
}

The animation may require all properties of the context to respond to a refresh.

Evan Mulawski
I've tried that already, and it has no effect.
romrom
+1  A: 

If I understood your question correctly, it goes like this. When you add an animation to a CALayer, it creates a so-called presentation copy of that layer using initWithLayer:. The presentation layer contains actual animated state for each animation frame, while the original layer has the final state. The problem with animating your own properties is that CALayer does not copy them all in initWithLayer:. If that's your case, your should override initWithLayer: and set up all the properties you need for animation, that is, both tint and radius.

Costique
Perfect you're right that solved the issue! Thanks a lot :)
romrom
You're welcome!
Costique