简体   繁体   中英

Custom CAGradientLayer doesn't animate

I've made a custom class of CAGradientLayer (added radial gradient option). I works but I can't figure out why I can't animate the colors.

Here's my code.

The animation is a simple CABasicAnimation where I set the toValue to a new array with colors.

#import "ExtCAGradientLayer.h"

NSString * const kExt_CAGradientLayerRadial = @"RadialGradient";

@implementation ExtCAGradientLayer
@synthesize gradientDrawingOptions;

+(BOOL)needsDisplayForKey:(NSString *)key
{
   return [key isEqualToString:@"type"] || [super needsDisplayForKey:key];
}

- (void)drawInContext:(CGContextRef)theContext
{
   if ([self.type isEqualToString:kExt_CAGradientLayerRadial]) {
    size_t num_locations = self.locations.count;

    int numbOfComponents = 0;
    CGColorSpaceRef colorSpace = NULL;

    if (self.colors.count) {
        CGColorRef colorRef = (__bridge CGColorRef)[self.colors objectAtIndex:0];
        numbOfComponents = CGColorGetNumberOfComponents(colorRef);
        colorSpace = CGColorGetColorSpace(colorRef);
    }

    float *locations = calloc(num_locations, sizeof(float));
    float *components = calloc(num_locations, numbOfComponents * sizeof(float));

    for (int x = 0; x < num_locations; x++) {
        locations[x] = [[self.locations objectAtIndex:x] floatValue];
        const CGFloat *comps = CGColorGetComponents((__bridge CGColorRef)[self.colors objectAtIndex:x]);
        for (int y = 0; y < numbOfComponents; y++) {
            int shift = numbOfComponents * x;
            components[shift + y] = comps[y];
        }
    }

    CGPoint position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    CGFloat radius = floorf(MIN(self.bounds.size.width, self.bounds.size.height) / 2);
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, num_locations);

    CGContextDrawRadialGradient(theContext, gradient, position, 0, position, radius, self.gradientDrawingOptions);

    free(locations);
    free(components);
}

Layers have a bunch of implicit animations tied to them. This can make them a little funny when interacting with CABasicAnimation . My first recommendation is to avoid CABasicAnimation when working with layers. There's almost never a good reason for it, since layers know how to animate themselves. It's much easier just to do this:

[CATransaction begin];
[CATransaction setAnimationDuration:3];
layer.colors = [NSArray arrayWithObjects:
              (__bridge id)[UIColor redColor].CGColor,
              [UIColor greenColor].CGColor,
              nil]; 
[CATransaction commit];

That's a 3-second animation of the colors. Easy. The begin/commit aren't technically needed in most cases, but they limit the scope of the setAnimationDuration: in case you're animating other things in this transaction.

But maybe you like CABasicAnimation , or you're using it something that returns them (I do that sometimes). You can still combine them with CALayer , but you have to tell CALayer to stop its automatic animation ( setDisableActions: ). And you still want to use the layer setters rather than toValue: .

[CATransaction begin];
[CATransaction setDisableActions:YES];
CABasicAnimation *anim = [[CABasicAnimation alloc] init];
anim.duration = 3;
[layer addAnimation:anim forKey:@"colors"];
layer.colors = [NSArray arrayWithObjects:
                (__bridge id)[UIColor redColor].CGColor,
                [UIColor greenColor].CGColor,
                nil];
[CATransaction commit];

If you use toValue: rather than the setter, it will work, but will "jump back" to the original value at the end.

Avoid solutions that suggest setting fillMode and removedOnCompletion . These generate many subtle problems if you don't understand exactly what they're doing. They seldom are what you really mean; they just happen to work as long as things are very simple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM