CAAnimation不提供分配除标准“animationDidStart:”/“animationDidStop:”方法之外的回调函数的机制。替代使用CABasicAnimation回调?
我有一个自定义的UIControl,它使用了2个重叠的CALayers。这种控制的目的类似于一个老式的声纳。顶层的内容包含一个不断旋转的图像(称之为“魔杖”)。该层下面是一个“spriteControl”层,当魔杖越过它们时呈现闪烁。
blips表示的对象被spriteControl预取并组织成不可见的CAShapeLayers。我正在使用CABasicAnimation一次旋转魔杖10度,然后利用“animationDidStop:”方法调用spriteControl上的一个方法,该方法使用魔杖图层的当前旋转值(又称为标题),并将Alpha设置的动画设置为1.0到0.0用于模拟闪烁和淡出效果。最后,这个过程无限期地重新开始。
虽然这种使用CAAnimation回调的方法确保了棒到达“ping”位置(即10deg,20deg,270deg等)的时间总是与另一层中的blip的发光一致,这个问题每隔10度停止,重新计算和开始动画。
我可以产生一个NSTimer来激发一个查询魔杖表示层的角度来获取标题值的方法。然而,这使得难以保持魔杖和blip突出显示同步,并且/或者导致一些完全跳过。这个方法在这里有所讨论:How can I callback as a CABasicAnimation is animating?
所以我的问题是,是否有任何事情可以做,以提高棒图层旋转的性能,而无需使用OpenGL ES重新实现控件。 (我意识到这可以在OpenGL环境中轻松解决,但是,在这里使用它需要进行大量的重新设计,这是不值得的。)虽然性能问题很小,但我不能动摇那种感觉简单而明显的是,我可以做到这一点将允许魔杖无限期地动画,而不会暂停执行昂贵的旋转计算。
下面是一些代码:
- (void)rotateWandByIncrement
{
if (wandShouldStop)
return;
CGFloat newRotationDegree = (wandRotationDegree + WAND_INCREMENT_DEGREES);
if (newRotationDegree >= 360)
newRotationDegree = 0;
CATransform3D rotationTransform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(newRotationDegree), 0, 0, 1);
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.toValue = [NSValue valueWithCATransform3D:rotationTransform];
animation.duration = WAND_INCREMENT_DURATION;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = FALSE;
animation.delegate = self;
[wandLayer addAnimation:animation forKey:@"transform"];
}
- (void)animationDidStart:(CAAnimation *)theAnimation
{
if (wandShouldStop)
return;
NSInteger prevWandRotationDegree = wandRotationDegree - WAND_INCREMENT_DEGREES;
if (prevWandRotationDegree < 0)
prevWandRotationDegree += 360;
// Pulse the spriteControl
[[self spriteControl] pulseRayAtHeading:prevWandRotationDegree];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
// update the rotation var
wandRotationDegree += WAND_INCREMENT_DEGREES;
if (wandRotationDegree >= 360)
wandRotationDegree = 0;
// This applies the rotation value to the model layer so that
// subsequent animations start where the previous one left off
CATransform3D rotationTransform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(wandRotationDegree), 0, 0, 1);
[CATransaction begin];
[CATransaction setDisableActions:TRUE];
[wandLayer setTransform:rotationTransform];
[CATransaction commit];
//[wandLayer removeAnimationForKey:@"transform"];
[self rotateWandByIncrement];
}
更新:我已经通过创建一个预先计算值的静态数组来消除所有不必要的计算。现在我已经向自己保证,我的性能瓶颈不是昂贵的数学操作造成的。然后,我在魔杖层上实现了关键帧动画,但仍然获得稍微不平滑的旋转。我发现切换到UIView动画而不是CAAnimation在这种情况下提供了更流畅的动画。到目前为止,似乎要从CAAnimation中获得任何真正的性能优势,您希望避免完全使用回调并让GPU实现其功能。 – quickthyme 2011-05-17 18:23:51