我想创建这样的东西,只考虑单循环以及它如何完成一个圆并在完成时反转它:
这段代码完成了我想要的一半:
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
drawAnimation.duration = 1;
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.0f];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circleLayer addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
我试过它反转但不起作用:
[CATransaction begin];
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
drawAnimation.duration = 1;
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.0f];
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
//[circleLayer addAnimation:drawAnimation forKey:@"drawCircleAnimation"];
[CATransaction setCompletionBlock:^{
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation2.duration = 1;
animation2.fromValue = [NSNumber numberWithFloat:0.0f];
animation2.toValue = [NSNumber numberWithFloat:1.0f];
animation2.removedOnCompletion = NO;
animation2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[circleLayer addAnimation:animation2 forKey:@"circelBack"];
}];
[circleLayer addAnimation:drawAnimation forKey:@"circleFront"];
[CATransaction commit];
问题是我无法扭转动画。
首先,我怀疑你的动画关键路径是错误的。首先应该将笔划结束的动画从0设置为1,然后笔划从0开始为1。
其次,您永远不会使用新值更新模型图层 - 因此,当动画完成时,图层将“快速恢复”到其原始状态。对你而言,这意味着当第一个动画完成时 - strokeStart
会回弹到0.0
- 因此反向动画看起来很奇怪。
要更新模型图层值,您只需在disableActions
块中将YES
设置为CATransaction
,以防止在图层属性更改时生成隐式动画(不会影响显式动画)。然后,在将动画添加到图层后,您将需要更新模型图层的属性。
此外,您可以重复使用CAAnimations - 因为它们在添加到图层时会被复制。因此,您可以为正向和反向动画定义相同的动画,只需更改关键路径即可。
如果您正在重复动画,则可能需要将动画定义为ivar - 并且只需在添加动画之前更新关键路径。
例如,在你的viewDidLoad
中:
@implementation ViewController {
CABasicAnimation* drawAnimation;
}
- (void)viewDidLoad {
[super viewDidLoad];
// define your animation
drawAnimation = [CABasicAnimation animation];
drawAnimation.duration = 1;
// use an NSNumber literal to make your code easier to read
drawAnimation.fromValue = @(0.0f);
drawAnimation.toValue = @(1.0f);
// your timing function
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// kick off the animation loop
[self animate];
}
然后,您需要创建一个animate
方法,以便执行动画的一次迭代。不幸的是,由于Core Animation不支持在序列中重复多个动画,因此您必须使用递归来实现效果。
例如:
-(void) animate {
if (self.circleLayer.superlayer) { // check circle layer is the layer heirachy before attempting to animate
// begin your transaction
[CATransaction begin];
// prevent implicit animations from being generated
[CATransaction setDisableActions:YES];
// reset values
self.circleLayer.strokeEnd = 0.0;
self.circleLayer.strokeStart = 0.0;
// update key path of animation
drawAnimation.keyPath = @"strokeEnd";
// set your completion block of forward animation
[CATransaction setCompletionBlock:^{
// weak link to self to prevent a retain cycle
__weak typeof(self) weakSelf = self;
// begin new transaction
[CATransaction begin];
// prevent implicit animations from being generated
[CATransaction setDisableActions:YES];
// set completion block of backward animation to call animate (recursive)
[CATransaction setCompletionBlock:^{
[weakSelf animate];
}];
// re-use your drawAnimation, just changing the key path
drawAnimation.keyPath = @"strokeStart";
// add backward animation
[weakSelf.circleLayer addAnimation:drawAnimation forKey:@"circleBack"];
// update your layer to new stroke start value
weakSelf.circleLayer.strokeStart = 1.0;
// end transaction
[CATransaction commit];
}];
// add forward animation
[self.circleLayer addAnimation:drawAnimation forKey:@"circleFront"];
// update layer to new stroke end value
self.circleLayer.strokeEnd = 1.0;
[CATransaction commit];
}
}
要停止动画,可以从超级图层中删除图层 - 或者实现自己的布尔检查以确定动画是否应该继续。