我正在制作一个我想制作动画的圆形进度条。一切都按预期绘制并且有效,但是当我尝试动画时,我立即改变而不是动画。任何帮助将不胜感激。
这是我的图层:
@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代码,之后我才知道我必须将它放在一个层中以使其生成动画,而且我还没有' t转换了所有东西),但我从Apple下载的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
只绘制一个圆圈,其中包含进度圆圈。 drawProgressInContext
是我期望动画的绘图代码。 Erica Sadun的iOS绘图中有一些辅助函数做了一些我没有包含的上下文和路径操作,函数名称应该是相当自我解释的。
非常感谢任何帮助。
仅供参考:如果这更容易,我非常愿意将其作为一个明确的动画,但我最终朝着这个方向前进,因为我也无法做到这一点。
答案 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)