2016-04-19 35 views
0

我正在研究一个我想要动画的圆形进度条。一切都按预期绘制并运行,但是当我尝试动画时,我会立即改变而不是动画。任何帮助,将不胜感激。CALayer上的隐式动画不是动画

这里是我的层:

@interface CircularProgressLayer : CALayer 

@property (nonatomic, assign) CGFloat progressDegrees; 
@property (nonatomic, assign) CGFloat trackWidth; 

@end 

@implementation CircularProgressLayer : CALayer 

@dynamic progressDegrees; 
@dynamic trackWidth; 

- (id)initWithLayer:(id)layer 
{ 
    if ((self = [super initWithLayer:layer])) 
    { 
     if ([layer isKindOfClass:[CircularProgressLayer class]]) 
     { 
      self.progressDegrees = ((CircularProgressLayer*)layer).progressDegrees; 
     } 
    } 

    return self; 
} 

// Instruct to Core Animation that a change in the custom property should automatically trigger a redraw of the layer. 
+ (BOOL)needsDisplayForKey:(NSString*)key 
{ 
    if ([key isEqualToString:@"progressDegrees"]) 
    { 
     return YES; 
    } 
    if ([key isEqualToString:@"trackWidth"]) 
    { 
     return YES; 
    } 

    return [super needsDisplayForKey:key]; 
} 

// Needed to support implicit animation of this property. 
// Return the basic animation the implicit animation will leverage. 
- (id<CAAction>)actionForKey:(NSString *)key 
{ 
    if ([key isEqualToString:@"progressDegrees"]) 
    { 
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key]; 
     animation.fromValue = [[self presentationLayer] valueForKey:key]; 
     animation.duration = 5.0; 
     animation.fillMode = kCAFillModeForwards; 
     animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 

     return animation; 
    } 
    return [super actionForKey:key]; 
} 

据我了解,在actionForKey:返回动画应该是所有需要做的动画作品,但我什么也没得到。我的所有绘图目前都包含在我的视图的drawLayer:inContext:方法中,该方法实现了此图层(因为它在我学会了必须将其放置到一个图层中以使其生成动画之前就已经创建为drawRect代码,并且我还没有将所有内容),但我从苹果下载的sample code使它看起来像这就好了。

这里是绘图代码:

-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context 
{ 
    UIGraphicsPushContext(context); 
    [self drawTrackInContext:context]; 
    [self drawProgressInContext:context]; 
    UIGraphicsPopContext(); 
} 

- (void)drawProgressInContext:(CGContextRef)context 
{  
    if (self.progress < 1) 
    { 
     // No progress, get out 
     return; 
    } 

    CGSize size = self.bounds.size; 

    FlipContextVertically(size); 
    CGContextSaveGState(context); 
    { 
     UIBezierPath *circle = [self circle]; 
     CGContextSetLineWidth(context, 0.0); 

     CGFloat degrees = 360.0; 

     for (int i = 0; i < degrees; i++) 
     { 
      if (i > ((RMONCircularProgressLayer *)self.layer).progressDegrees) 
      { 
       break; 
      } 

      CGFloat theta = 2 * M_PI * (CGFloat) i/degrees; 
      CGFloat x = self.radius * sin(theta); 
      CGFloat y = self.radius * cos(theta); 

      MovePathCenterToPoint(circle, CGPointMake(x, y)); 
      OffsetPath(circle, CGSizeMake(size.width/2, size.height/2)); 

      CGContextSetFillColorWithColor(context, [self colorForDegree:i].CGColor); 
      CGContextAddPath(context, circle.CGPath); 
      CGContextDrawPath(context, kCGPathFillStroke); 
     } 
    } 
    CGContextRestoreGState(context); 
} 

- (void)drawTrackInContext:(CGContextRef)context 
{ 
    CGContextSaveGState(context); 
    { 
     // Draw the circle covering middle of the screen 
     CGSize size = self.bounds.size; 

     CGContextSetLineWidth(context, self.trackWidth); // will only be filled color 

     CGContextSetStrokeColorWithColor(context, self.trackColor.CGColor); 
     CGContextSetFillColorWithColor(context, self.fillColor.CGColor); 
     CGContextSetAlpha(context, 1.0); 

     CGContextAddArc(context, (CGFloat)size.width/2.0, (CGFloat)size.height/2.0, self.radius, 0, (CGFloat)M_PI*2.0, 1); 
     CGContextDrawPath(context, kCGPathFillStroke); 
    } 
    CGContextRestoreGState(context); 
} 

drawTrackInContext只是画一个圆圈,在圆的进展将被包含。 是我期望生成动画的绘图代码。有一些来自iOS Drawing的助手函数Erica Sadun做了一些我没有包括的上下文和路径操作,函数名应该是相当自我解释的。

任何帮助将不胜感激。

仅供参考:如果这更容易,我更愿意将其作为一个明确的动画,但是我最终走向了这个方向,因为我也无法做到这一点。

+0

请在'drawLayer:inContext:' –

+0

内显示您的代码添加了绘图代码,不知道为什么我忘了它。 –

回答

2

当一个图层属性设置为动画时,该属性的值不会随着时间而改变以表示中间值。相反,层时间中给定时刻的属性值来自活动动画,并可在图层的presentationLayer中使用。

动画处于活动状态时,会在表示层上调用drawInContext:而不是主层。同样,-drawLayer:inContext:接收表示层而不是主层。

您遇到的问题是-drawProgressInContext:不使用调用函数中的图层,而是读取self.layer.progressDegrees以获取要绘制的值,该值始终为分配的值。解决方法是在层传递给函数和读出的值:

- (void)drawProgressInLayer:(CALayer *)layer context:(CGContextRef)context 
{ 
    ... 
    if (i > ((RMONCircularProgressLayer *)layer).progressDegrees) { 
     ... 

你也有一个问题,当你放弃对if (self.progress < 1)。当从非零值变为零时,这将使其无法生成动画。同样的修复将适用:if ((RMONCircularProgressLayer *)layer).progressDegrees < 1)

+0

感谢您的详细解释。我碰到使用表示层值来获得动画效果,但我不得不添加一个if(isAnimating)块来在2之间进行转换,并且我知道它必须更容易。我没有意识到我的绘图代码是用2个不同的图层调用的。真棒。 –