替代使用CABasicAnimation回调?

时间:2011-03-07 01:33:54

标签: calayer nstimer caanimation cabasicanimation cashapelayer

CAAnimation不提供分配标准“animationDidStart:”/“animationDidStop:”方法之外的回调函数的机制。

我有一个自定义UIControl,它使用2个重叠的CALayer。这种控制的目的类似于老式的声纳。顶层的内容包含一个不断旋转的图像(称此图层为“魔杖”)。在该图层下面是一个“spriteControl”图层,当魔杖经过它们时会呈现blips。

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

1 个答案:

答案 0 :(得分:1)

让我们说雷达需要10秒才能完成一次旋转。

要让魔杖无限旋转,请将CABasicAnimation附加到Duration,其RepeatCount属性设置为10,其CAKeyframeAnimation属性设置为1e100f。

每个blip都可以使用自己的实例{{1}}进行动画处理。我不会写详细信息,但是对于每个blip,你指定一个不透明度值数组(我假设不透明度是你淡出blip的方式)和一组时间百分比(参见Apple的文档)。