为什么当我为我的CABasicAnimation设置一个较低的持续时间值时,它会跳转吗?
示例项目: http : //cl.ly/1W3V3b0D2001
我使用CABasicAnimation
来创build一个像饼图一样的进度指示器。 类似于iOS 7的应用程序下载animation:
animation设置如下:
- (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; }
通过设置视图的进度触发animation:
- (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
,则animation会跳转。 它顺时针转动一点,跳回去,然后像往常一样继续前进。 如果持续时间或进度设置得更高 , 则不会发生这种情况 。
我该如何阻止跳跃? 除非进度非常低,否则这段代码在每种情况下都能正常工作。 我究竟做错了什么?
啊! 早些时候我们应该看到这一点。 问题是你的if (animated)
块的这一行:
self.innerPie.strokeEnd = progress;
由于innerPie是一个核心animation层,这会导致一个隐含的animation(大多数属性更改)。 这个animation是与你自己的animation战斗。 您可以通过在设置strokeEnd时禁用隐式animation来防止发生这种情况:
[CATransaction begin]; [CATransaction setDisableActions:YES]; self.innerPie.strokeEnd = progress; [CATransaction commit];
(请注意setDisableActions:
如何在开始/提交内。)
或者,您可以删除自己的animation,并使用自动animation,使用setAnimationDuration:
东西setAnimationDuration:
来改变它的长度。
原始意见:
我的猜测是你的drawRect:
被调用,它会重置你的strokeEnd值。 这些图层可能不应该在drawRect:
设置drawRect:
无论如何。 尝试将该设置移动到init方法或didMoveToWindow:
或类似的。
如果这没有效果,我会build议每次调用方法时添加日志语句来跟踪progress
值和[self.innerPie.presentationLayer strokeEnd]
; 也许他们没有做你期望的事情。
你为什么使用drawRect:? 在你的class级中不应该有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; }
在相同距离内行驶时,时间越短,速度越高。 当你设定的时间太短,速度会非常高,这就是为什么它看起来像跳跃。