ios - 为什么当我为我的 CABasicAnimation 设置一个较低的持续时间值时它会跳转?

标签 ios objective-c uiview core-animation cabasicanimation

示例项目: http://cl.ly/1W3V3b0D2001

我正在使用 CABasicAnimation 创建一个类似于饼图的进度指示器。类似于 iOS 7 应用程序下载动画:

enter image description here

动画设置如下:

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];

    CGFloat radius = CGRectGetWidth(self.frame) / 2;
    CGFloat inset  = 1;
    CAShapeLayer *ring = [CAShapeLayer layer];
    ring.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                           cornerRadius:radius-inset].CGPath;

    ring.fillColor = [UIColor clearColor].CGColor;
    ring.strokeColor = [UIColor whiteColor].CGColor;
    ring.lineWidth = 2;

    self.innerPie = [CAShapeLayer layer];
    inset = radius/2;
    self.innerPie.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.bounds, inset, inset)
                                               cornerRadius:radius-inset].CGPath;
    self.innerPie.fillColor = [UIColor clearColor].CGColor;
    self.innerPie.strokeColor = [UIColor whiteColor].CGColor;
    self.innerPie.lineWidth = (radius-inset)*2;

    self.innerPie.strokeStart = 0;
    self.innerPie.strokeEnd = 0;

    [self.layer addSublayer:ring];
    [self.layer addSublayer:self.innerPie];

    self.progress = 0.0;
}

通过设置 View 的进度来触发动画:

- (void)setProgress:(CGFloat)progress animated:(BOOL)animated {
    self.progress = progress;

    if (animated) {
        CGFloat totalDurationForFullCircleAnimation = 0.25;

        CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        self.innerPie.strokeEnd = progress;
        pathAnimation.delegate = self;
        pathAnimation.fromValue = @([self.innerPie.presentationLayer strokeEnd]);
        pathAnimation.toValue = @(progress);
        pathAnimation.duration = totalDurationForFullCircleAnimation * ([pathAnimation.toValue floatValue] - [pathAnimation.fromValue floatValue]);

        [self.innerPie addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
    }
    else {
        [CATransaction setDisableActions:YES];
        [CATransaction begin];
        self.innerPie.strokeEnd = progress;
        [CATransaction commit];
    }
}

但是,在我将进度设置为较小的值(例如 0.25)的情况下,动画中会出现跳跃。它顺时针向前一点,向后跳,然后像往常一样继续前进。值得一提的是,如果将持续时间或进度设置得更高,则不会发生这种情况

如何停止跳跃?除了进度非常低的情况外,此代码在所有情况下都运行良好。我做错了什么?

最佳答案

啊!我们应该早点看到这一点。问题是您的 if (animated) block 中的这一行:

self.innerPie.strokeEnd = progress;

由于 innerPie 是核心动画层,这会导致隐式动画(大多数属性更改都会这样做)。这个动画是在和你自己的动画打架。您可以通过在设置 strokeEnd 时禁用隐式动画来防止这种情况发生:

[CATransaction begin];
[CATransaction setDisableActions:YES];
self.innerPie.strokeEnd = progress;
[CATransaction commit];

(注意 setDisableActions: 是如何在 begin/commit 中的。)

或者,您可以删除自己的动画,只使用自动动画,使用类似 setAnimationDuration: 的东西来改变它的长度。

原始建议:

我的猜测是您的 drawRect: 正在被调用,这会重置您的 strokeEnd 值。无论如何,这些层可能不应该在 drawRect: 中设置。尝试将该设置移动到 init 方法或 didMoveToWindow: 或类似方法。

如果这没有效果,我建议添加日志语句来跟踪每次调用方法时 progress[self.innerPie.presentationLayer strokeEnd] 的值;也许他们没有按照您的预期行事。

关于ios - 为什么当我为我的 CABasicAnimation 设置一个较低的持续时间值时它会跳转?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22521690/

相关文章:

ios - 找不到 iOS 开发证书

objective-c - 组织多个依赖的 Objective-C 库的最佳方式是什么?

iphone - 应用程序适用于模拟器但不适用于设备

ios - 如果用户禁用了应用程序的推送,是否可以进行静默远程通知?

ios uiview 自动展开尺寸

iphone - 有没有办法可以在 iPhone SDK 上制作叠加 View ?

c# - 如果手机已锁定,则在后台继续 iOS 中的任务

iphone - 什么类型的应用程序允许在 iPhone 中自动启动?

ios - 分发证书自动吊销

ios - UIScrollView 中的 touchesBegan 调用了两次