为啥当我为我的 CABasicAnimation 设置低持续时间值时它会跳跃?
Posted
技术标签:
【中文标题】为啥当我为我的 CABasicAnimation 设置低持续时间值时它会跳跃?【英文标题】:Why when I set a low duration value for my CABasicAnimation does it jump?为什么当我为我的 CABasicAnimation 设置低持续时间值时它会跳跃? 【发布时间】:2014-03-20 01:29:29 【问题描述】:示例项目: http://cl.ly/1W3V3b0D2001
我正在使用CABasicAnimation
创建一个类似于饼图的进度指示器。类似于 ios 7 应用下载动画:
动画设置如下:
- (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;
通过设置视图的进度来触发动画:
- (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
,动画中会出现跳跃。它顺时针向前一点,然后向后跳,然后像往常一样继续向前。 如果将持续时间或进度设置得更高,则不会发生这种情况,这毫无价值。
如何停止跳跃?此代码在所有情况下都运行良好,除非进度非常低。我做错了什么?
【问题讨论】:
不要在begin
和commit
之外配置事务。你最终可能会影响其他事情。
【参考方案1】:
啊!我们应该早点看到这一点。问题是if (animated)
块中的这一行:
self.innerPie.strokeEnd = progress;
由于 innerPie 是一个核心动画层,这会导致隐式动画(大多数属性更改都会这样做)。该动画正在与您自己的动画战斗。您可以通过在设置 strokeEnd 时禁用隐式动画来防止这种情况发生:
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.innerPie.strokeEnd = progress;
[CATransaction commit];
(注意setDisableActions:
在开始/提交中的位置。)
或者,您可以删除自己的动画并只使用自动动画,使用 setAnimationDuration:
之类的东西来更改其长度。
原建议:
我的猜测是您的 drawRect:
正在被调用,这会重置您的 strokeEnd 值。无论如何,这些层可能不应该在drawRect:
中设置。尝试将该设置移至 init 方法或didMoveToWindow:
或类似方法。
如果这不起作用,我建议在每次调用该方法时添加日志语句来跟踪progress
和[self.innerPie.presentationLayer strokeEnd]
的值;也许他们没有做你期望的事情。
【讨论】:
嗯,我将它移出drawRect
,并在调用setProgress:animated:
时开始记录,但都没有帮助。日志记录仅在第一次调用 strokeEnd 和 progress 时显示 0.0 以将其设置为 0.1,这是唯一一次调用它。这是一个示例项目:cl.ly/1W3V3b0D2001
@DougSmith 根据您的示例项目,我已经更新了我的答案。
这是证明解决方案的documentation 的链接。【参考方案2】:
你为什么使用drawRect:?你的类中应该没有drawRect:
方法。
如果你也在使用 self.layer,你不应该使用 drawRect。使用其中一种,不要同时使用。
将其更改为:
- (id)initWithFrame:(CGRect)frame
if (!(self = [super initWithFrame:frame])
return nil;
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;
return self;
【讨论】:
我将它移出drawRect
,但没有任何改变。这是一个示例项目:cl.ly/1W3V3b0D2001
将其移至 initWithFrame 是正确的做法,但并没有解决问题。抱歉,我以前从未与CAShapeLayer
合作过,但是我查看了您的代码并在进行此更改后:dl.dropboxusercontent.com/u/147461/… 它完美运行(动画:是)。我不确定你如何让它与动画一起工作:NO,并且没有明显的方法来控制动画速度。我必须进一步研究 CAShapeLayer。
基本上看起来 CAShapeLayer 为你做了所有的动画工作,如果你尝试在上面添加自己的动画,它就会失败。大概有一些方法可以正确地制作动画,我不确定它是什么。【参考方案3】:
在相同距离内行驶时,持续时间越短,速度越高。当你将持续时间设置得太小时,速度会非常高,这就是为什么它看起来像跳跃的原因。
【讨论】:
这不是正在发生的事情。正如我上面所描述的,它会向前跳跃,这将是完美的,然后它会跳回到原来的起点然后重新开始。这不是高速的结果。以上是关于为啥当我为我的 CABasicAnimation 设置低持续时间值时它会跳跃?的主要内容,如果未能解决你的问题,请参考以下文章
当我将条目插入现有部分时,为啥我的 UITableView 会为我添加另一个部分?
为啥当我单击一个链接时,它会为我的所有链接执行该功能? (Javascipt)