2

我正在尝试像这样为 a 制作CAEmitterLayer动画emitterPosition

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"emitterPosition.x"] ;
animation.toValue = (id) toValue ;
animation.removedOnCompletion = NO ;
animation.duration = self.translationDuration ;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ;
animation.completion = ^(BOOL finished)
    {
    [self animateToOtherSide] ;
    } ;
[_emitterLayer addAnimation:animation forKey:@"emitterPosition"] ;
CGPoint newEmitterPosition = CGPointMake(toValue.floatValue, self.bounds.size.height/2.0) ;
_emitterLayer.emitterPosition = newEmitterPosition ;

请注意,它animation.completion是在仅调用相应CAAnimation委托方法的类别中声明的。

问题是它根本没有动画,而是将发射器显示在其最终位置。我的印象是,一旦将动画添加到图层,就应该将其后面的实际模型更改为其最终位置,以便在动画完成时模型处于其最终状态;即,防止动画“弹回”到其原始位置。

我尝试将最后两行放在animation.completion块中,这确实像预期的那样动画。但是,当动画结束时,一些粒子会间歇性地在发射器的原始位置发射。如果您将系统置于负载下(例如,在播放动画时滚动 tableview),这种情况会更频繁地发生。

我正在考虑的另一个解决方案是根本不移动emitterPosition,而只是移动CAEmitterLayer本身,尽管我还没有尝试过。

提前感谢您提供的任何帮助。

4

1 回答 1

6

也许emitterPosition.x不是动画的有效关键路径。尝试emitterPosition改用(因此您必须提供封装在 NSValue 中的 CGPoint 值)。

我只是在我自己的机器上试过这个,它工作正常:

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"emitterPosition"];
ba.fromValue = [NSValue valueWithCGPoint:CGPointMake(30,100)];
ba.toValue = [NSValue valueWithCGPoint:CGPointMake(200,100)];
ba.duration = 6;
ba.autoreverses = YES;
ba.repeatCount = HUGE_VALF;
[emit addAnimation:ba forKey:nil];

其他需要考虑的事情:

  • 您通常可以使用 nil 作为 中的键addAnimation:forKey:,除非您以后需要找到此动画(例如,删除它或以某种方式覆盖它)。关键路径很重要。

  • 设置removedOnCompletion为 NO 几乎总是错误的,并且通常是无赖的最后避难所(即由于不了解动画的工作原理)。

  • 如果,正如你所说,_emitterLayer.emitterPosition = newEmitterPosition在完成块内设置动画,那么你为什么要使用 CABasicAnimation 呢?为什么不直接调用 UIViewanimate...并在动画块中设置emitterPosition?如果可行,它将用一块石头杀死两只鸟,移动位置并对其进行动画处理。

于 2012-11-30T21:41:22.453 回答