ios - CALayer 上的隐式动画没有动画

标签 ios objective-c animation core-animation 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: 中返回动画应该是使动画工作所需的全部,但我什么也没得到。我的所有绘图当前都包含在实现此层的 View 的 drawLayer:inContext: 方法中(因为它起源于 drawRect 代码,然后我才知道我必须将它放在一个层中才能将其显示出来)动画,我还没有把所有东西都转换过来),但是 sample code我是从 Apple 下载的,看起来还不错。

下面是绘图代码:

-(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 Drawing 中有一些辅助函数可以执行一些我没有包括的上下文和路径操作,函数名称应该是相当 self 解释的。

如有任何帮助,我们将不胜感激。

仅供引用:如果更容易的话,我非常愿意将其制作成明确的动画,但我最终朝这个方向前进,因为我也无法做到这一点。

最佳答案

当图层属性被动画化时,该属性的值不会随时间变化以表示中间值。相反,图层时间中给定时刻的属性值源自事件动画,并在图层的 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)

关于ios - CALayer 上的隐式动画没有动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36706364/

相关文章:

jquery - 仅在 Firefox 中中止 jQuery.fadeTo 时内容不可见半秒

ios - 关闭应用程序后如何调试

ios - 如何创建具有不同颜色的贝塞尔曲线路径?

objective-c - 检查核心数据中是否存在对象的最快方法?

ios - 城市数据/统计信息Api

c# - unity animation.play() 不起作用

iphone - 如何扩展我检查 2 张卡是否匹配到 3 张匹配的卡的方法?

ios - 根据 segue 重定向到不同的 ViewControllers

objective-c - 如何为代码自动格式化设置 Xcode 插件

java - 动画对象在两点之间移动