最近在公司项目中有很多动效处理,在做一个先上下后左右进行阻尼运动时,本人是通过Core Animation中的CASpringAnimation进行实现。
实现思路:将整个动画拆分为两块:先做上下阻尼运动,再做左右阻尼运动。
iOS 9中Apple自带了CASpringAnimation,因此添加两个连续的阻尼动画,就可以实现想要的效果。先上代码:
- (void)shakeAnimationForView {
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:@"position.y"];
springAnimation.damping = 1;
springAnimation.stiffness = 300;
springAnimation.mass = 1;
springAnimation.initialVelocity = 0;
springAnimation.fromValue = @(self.locusAnimationView.center.y);
springAnimation.toValue = @(self.locusAnimationView.center.y - 5);
springAnimation.repeatCount = 1;
springAnimation.duration = 0.5;
springAnimation.delegate = self;
springAnimation.autoreverses = YES;
[self.locusAnimationView.layer addAnimation:springAnimation forKey:@"positionY"];
}
以上是做上下阻尼运动,So nice! 运行起来正是需要的结果。然后实现CAAnimationDelegate,在第一个动画完成后,开始左右阻尼运动:
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if ([anim isEqual:[self.locusAnimationView.layer animationForKey:@"positionX"]]) {
[self shakeAnimationForView:self.locusAnimationView];
return;
}
[self.locusAnimationView.layer removeAllAnimations];
if (flag) {
CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:@"position.x"];
springAnimation.damping = 1;
springAnimation.stiffness = 300;
springAnimation.mass = 1;
springAnimation.initialVelocity = 0;
springAnimation.fromValue = @(self.locusAnimationView.center.x);
springAnimation.toValue = @(self.locusAnimationView.center.x + 5);
springAnimation.duration = 0.5;
springAnimation.repeatCount = 1;
springAnimation.delegate = self;
springAnimation.autoreverses = YES;
[self.locusAnimationView.layer addAnimation:springAnimation forKey:@"positionX"];
}
}
恩,就这样,大功告成,我们先Run起来看看是不是跟预期的效果一致。我擦,什么鬼!做了一次上下阻尼后一直重复左右阻尼运动。这跟我们要的效果完全不一样啊。然后断点调试,发现在CAAnimationDelegate中通过[self.locusAnimationView.layer animationForKey:@"positionX"]获取不到CAAnimation的对象,因此
if ([anim isEqual:[self.locusAnimationView.layer animationForKey:@"positionX"]]) {
[self shakeAnimationForView:self.locusAnimationView];
return;
}
该判断一直跳过,所以重复进行左右阻尼运动。那到底是什么原因造成通过animationForKey找不到对应的Animation对象呢?
经过半天折腾,在stackover上终于找到了答案。
对于Core Aniamtion中有个属性removedOnCompletion,默认为YES,表示当动画完成时把这个动画移除,因此通过上述方式一直找不到对应的CAAnimation。现在我们把这个属性添加到我们以上两段代码中并设为NO,表示动画结束后不移除,再run下,结果正是我们想要的。