我希望实现循环进度,并且可以动态设置进度值。代码如下:
- (CGPoint)center {
return CGPointMake(self.view.frame.origin.x + self.view.frame.size.width / 2.0,
self.view.frame.origin.y + self.view.frame.size.height / 2.0);
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
CGMutablePathRef roundPath = CGPathCreateMutable();
CGPathAddArc(roundPath, NULL, self.center.x, self.center.y,
20,
2 * M_PI + M_PI_2,
M_PI_2,
YES);
CAShapeLayer *backgroundLayer = [CAShapeLayer layer];
backgroundLayer.frame = self.view.layer.bounds;
backgroundLayer.path = roundPath;
backgroundLayer.strokeColor = [[NSColor blueColor] CGColor];
backgroundLayer.fillColor = nil;
backgroundLayer.lineWidth = 10.0f;
backgroundLayer.lineJoin = kCALineJoinBevel;
[self.view.layer addSublayer:backgroundLayer];
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.view.layer.bounds;
pathLayer.path = roundPath;
pathLayer.strokeColor = [[NSColor whiteColor] CGColor];
pathLayer.fillColor = nil;
pathLayer.lineWidth = 10.0f;
pathLayer.lineJoin = kCALineJoinBevel;
[self.view.layer addSublayer:pathLayer];
self.pathLayer = pathLayer;
[self start];
}
- (void)start {
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 0.01;
pathAnimation.fromValue = [NSNumber numberWithFloat:self.progress];
pathAnimation.toValue = [NSNumber numberWithFloat:self.progress+0.01];
[self.pathLayer setStrokeEnd:self.progress + 0.01];
[pathAnimation setDelegate:self];
[self.pathLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
self.progress += 0.01;
if (self.progress < 1.0) {
[self start];
}
}
我发现当我将持续时间设置为0.1f甚至更大时,它会正常工作。但是如果我将持续时间设置为0.01f,则动画将不会从正确的值开始,它将从更大的值开始动画减少到正确的值。所以整个动画总是闪现,任何人都有同样的问题或知道为什么?非常感谢!
答案 0 :(得分:3)
originaluser2可能是关于具体原因的,但这种设计是不正确的。
在60fps时,一帧为0.0167s。您要求在不到一帧的情况下为更改设置动画。每个动画都有自己的媒体时间(kCAMediaTimingFunctionDefault
),这意味着您可以通过动画创建复杂的上升/下降速度。无论如何,你的时间安排都会变得不稳定,因为你在每一步都会遇到一点错误(animationDidStop
可能需要稍微不同的时间来运行,具体取决于很多因素)。动画的全部意义在于你不需要做这种事情。这就是你有动画引擎的原因。
在您想要的时间内动画到progress
。不要尝试注入许多额外的动画步骤。注入步骤是动画引擎的作用。
CALayer
旨在为您完成大部分内容。你不需要为此创建明确的动画;只是使用隐含。像(未经测试,未编译)的东西:
- (void)setProgress: (CGFloat)progress {
double velocity = 1.0;
[CATransaction begin];
double delta = fabs(_progress - progress);
[CATransaction setAnimationDuration: delta * velocity];
[self.pathLayer setStrokeEnd: progress];
[CATransaction commit];
}
答案 1 :(得分:1)
作为Rob says,添加重复动画并不是最好的主意。他的解决方案可能很适合你。但是,如果您仍然坚持使用重复的动画,请修改当前代码:
问题是您在添加动画之前调用了这行代码。
[self.pathLayer setStrokeEnd:self.progress + 0.01];
这将在图层上创建隐式动画,因此当您添加显式动画时 - 它会导致问题(您正在观察的闪光)。
解决方案是在启动动画后更新CATransaction
中的模型层。您还需要将disableActions
设置为YES
,以防止生成隐式动画。
例如:
- (void)start {
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 0.01;
pathAnimation.fromValue = [NSNumber numberWithFloat:self.progress];
pathAnimation.toValue = [NSNumber numberWithFloat:self.progress+0.01];
[pathAnimation setDelegate:self];
[self.pathLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self.pathLayer setStrokeEnd:self.progress + 0.01];
[CATransaction commit];
}
虽然,值得注意的是,您只需使用CATransaction
和strokeEnd
的隐式动画即可创建动画。
例如:
- (void)start {
[CATransaction begin];
[CATransaction setAnimationDuration:0.01];
[CATransaction setCompletionBlock:^{
self.progress += 0.01;
if (self.progress < 1.0) {
[self start];
}
}];
[self.pathLayer setStrokeEnd:self.progress + 0.01];
[CATransaction commit];
}
这样你就不必在每次迭代时创建一个新的显式动画。