1

CAGradientLayer のカスタム クラスを作成しました (放射状グラデーション オプションを追加)。動作しますが、色をアニメーション化できない理由がわかりません。

これが私のコードです。

アニメーションは単純な CABasicAnimation で、toValue を色付きの新しい配列に設定します。

#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);
}
4

1 に答える 1

4

レイヤーには、暗黙的なアニメーションが多数関連付けられています。これにより、 とやり取りするときに少しおかしくなることがありCABasicAnimationます。CABasicAnimation私の最初の推奨事項は、レイヤーを操作するときは避けることです。レイヤーは自分自身をアニメーション化する方法を知っているため、正当な理由はほとんどありません。これを行うだけではるかに簡単です:

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

これは、色の 3 秒間のアニメーションです。簡単。ほとんどの場合、begin/commit は技術的には必要ありませんがsetAnimationDuration:、このトランザクションで他のものをアニメーション化する場合に備えて、begin/commit は の範囲を制限します。

しかしCABasicAnimation、あなたは が好きかもしれませんし、それらを返す何かを使用しているかもしれません (私は時々そうします)。と組み合わせることができますが、自動アニメーションを停止するCALayerように指示する必要があります ( )。そして、あなたはまだレイヤーセッターを使いたいと思っています.CALayersetDisableActions: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];

toValue:セッターではなく使用すると機能しますが、最後に元の値に「ジャンプ」します。

fillModeと の設定を提案する解決策は避けてくださいremovedOnCompletion。これらが何をしているのかを正確に理解していないと、多くの微妙な問題が発生します。それらがあなたが本当に意味するものであることはめったにありません。物事が非常に単純である限り、それらはたまたま機能します。

于 2012-06-25T17:44:13.657 に答える