ios - 自定义 CAGradientLayer 不设置动画

标签 ios caanimation cagradientlayer

我制作了一个 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);
}

最佳答案

图层有一堆与之相关的隐式动画。这可以让他们在与 CABasicAnimation 互动时变得有点滑稽。 .我的第一个建议是避免 CABasicAnimation使用图层时。几乎没有什么好的理由,因为图层知道如何为自己设置动画。这样做要容易得多:

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

这是一个 3 秒的颜色动画。简单的。在大多数情况下,技术上不需要开始/提交,但它们限制了 setAnimationDuration: 的范围。以防您在此事务中为其他事物设置动画。

但也许你喜欢 CABasicAnimation ,或者您正在使用它来返回它们(我有时会这样做)。您仍然可以将它们与 CALayer 结合使用, 但你必须告诉 CALayer停止其自动动画 (setDisableActions:)。你仍然想使用图层 setter 而不是 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:而不是setter,它会起作用,但最后会“跳回”到原始值。

避免建议设置 fillMode 的解决方案和 removedOnCompletion .如果您不完全了解它们在做什么,这些会产生许多微妙的问题。它们很少是你真正的意思。只要事情非常简单,它们就可以正常工作。

关于ios - 自定义 CAGradientLayer 不设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11159584/

相关文章:

objective-c - NSClassFromString(MyClassName) 比调用 MyClass 的类函数

ios - CALayer.timeOffset 何时可以使用

swift - 将图层蒙版设置为 UIBezierPath super View

ios - 应用多个 CAGradientLayer 来 mask View

ios - UITextField 中的渐变文本

ios - 如何在 Swift 代码中正确使用 #ifdef DEBUG/RELEASE 值?

ios - 即使我安装了 Cocoapods 并安装了 Dialogflow 的 pod 文件,Xcode 仍显示错误 'No such module'

ios - 如何将 "?x=123"之类的内容附加到 NSURL?

ios - 使用动画更改 UIView 背景颜色

ios - 如何给 CAGradientLayer "locations"