Альтернатива использованию обратных вызовов CABasicAnimation? - PullRequest
0 голосов
/ 07 марта 2011

CAAnimation не предоставляет механизм для назначения функций обратного вызова, кроме стандартных методов "animationDidStart:" / "animationDidStop:".

У меня есть пользовательский UIControl, который использует 2 CALayers, которые перекрываются.Цель этого контроля похожа на старомодный сонар.Содержимое верхнего слоя содержит изображение, которое постоянно вращается (назовите этот слой "палочкой").Под этим слоем находится слой «spriteControl», который визуализирует блики, когда палочка проходит над ними.

Объекты, которые представляют блики, предварительно извлекаются и организуются в невидимые CAShapeLayers с помощью spriteControl.Я использую CABasicAnimation для поворота палочки за раз на 10 градусов, а затем использую метод animationDidStop: для вызова метода в spriteControl, который принимает текущее значение вращения слоя палочки (он же заголовок) и анимирует настройку альфа изОт 1,0 до 0,0 для имитации эффекта всплеска и исчезновения.Наконец, процесс начинается снова бесконечно.

В то время как этот подход использования обратных вызовов CAAnimation гарантирует, что время, когда палочка достигает позиции «ping» (то есть 10deg, 20deg, 270deg и т. Д.) Всегда совпадает сосвещение бликов в другом слое, есть проблема остановки, пересчета и запуска анимации каждые 10 градусов.

Я мог бы вызвать NSTimer для запуска метода, который запрашивает угол представления палочкислой, чтобы получить значение заголовка.Однако это усложняет синхронизацию подсветки палочки и вспышки и / или приводит к тому, что некоторые из них вообще пропускаются.Этот подход немного обсуждается здесь: Как я могу сделать обратный вызов, так как анимация CABasicAnimation?

Поэтому мой вопрос заключается в том, могу ли я что-либо сделать, чтобы улучшить производительность палочкивращение слоя без переопределения элемента управления с использованием 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 Ответ

1 голос
/ 04 мая 2011

Допустим, радару требуется 10 секунд, чтобы совершить один полный оборот.

Чтобы палочка вращалась бесконечно, прикрепите к ней CABasicAnimation со свойством Duration, равным 10, и свойством RepeatCount, равным 1e100f.

Каждое сообщение может быть анимировано с использованием собственного экземпляра CAKeyframeAnimation. Я не буду писать подробности, но для каждого сообщения вы указываете массив значений непрозрачности (я предполагаю, что прозрачность - это то, как вы затухаете сообщения) и массив процентов времени (см. Документацию Apple).

...