我已经制作了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);
}
答案 0 :(得分:4)
图层有一堆与它们相关的隐式动画。这可以使他们在与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:
)。而且您仍然希望使用图层设置器而不是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
的解决方案。如果您不完全了解他们正在做什么,这些会产生许多微妙的问题。他们很少是你真正的意思;只要事情很简单,他们就会碰巧工作。