2011-03-07 27 views
0

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]; 
} 
+0

更新:我已经通过创建一个预先计算值的静态数组来消除所有不必要的计算。现在我已经向自己保证,我的性能瓶颈不是昂贵的数学操作造成的。然后,我在魔杖层上实现了关键帧动画,但仍然获得稍微不平滑的旋转。我发现切换到UIView动画而不是CAAnimation在这种情况下提供了更流畅的动画。到目前为止,似乎要从CAAnimation中获得任何真正的性能优势,您希望避免完全使用回调并让GPU实现其功能。 – quickthyme 2011-05-17 18:23:51

回答

1

比方说,这需要10秒的雷达,使一个完整的旋转。

为了让魔杖无限期地旋转,附加CABasicAnimation将它与它的Duration属性设置为10和RepeatCount属性设置为1e100f。

使用他们自己的实例CAKeyframeAnimation可以为每个blips分别设置动画。我不会写详细信息,但是对于每个blip,您都指定一个不透明度值的数组(我认为不透明度是您如何淡出blipped)和一系列时间百分比(请参阅Apple的文档)。

+0

有趣和感谢小费!目前,淡化效果是应用于每个CALayer单独运行的动画。我的问题是更多的魔杖相关,因为我希望它的传递时机触发单个blip图层上的动画。我考虑设置一个带有36个动画的CAAnimationGroup,每个动画都有一个延迟值,以便它们连续运行。我希望这可以给我animationDidStop回调每个动画。但是苹果的文档似乎表明,你只能获得整个团队的其中一个,而不是其中的每个动画。 – quickthyme 2011-05-11 23:12:16