Альтернатива использованию обратных вызовов CABasicAnimation?

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

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

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

В то время как этот подход с использованием обратных вызовов CAAnimation гарантирует, что время достижения стрелкой положения «пинга» (т. е. 10 градусов, 20 градусов, 270 градусов и т. , пересчитывая и запуская анимацию каждые 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];
}

person quickthyme    schedule 07.03.2011    source источник
comment
Обновление: с тех пор я устранил все ненужные вычисления, создав статический массив предварительно вычисленных значений. Теперь я убедился, что узкое место в моей производительности не вызвано дорогостоящими математическими операциями. Затем я применил анимацию ключевых кадров к слою с палочкой, но все же получил немного менее плавное вращение. Я действительно обнаружил, что переключение на анимацию UIView, а не CAAnimation, обеспечивает более плавную анимацию в этом случае. Пока кажется, что для получения реального выигрыша в производительности от CAAnimation вы хотите вообще избежать использования обратных вызовов и просто позволить графическому процессору делать свое дело.   -  person quickthyme    schedule 17.05.2011


Ответы (1)


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

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

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

person pe8ter    schedule 04.05.2011
comment
Интересно и спасибо за подсказку! В настоящее время эффект затухания представляет собой анимацию, применяемую к каждому сообщению CALayer, которое запускается отдельно. Моя проблема больше связана с палочкой, так как я хочу, чтобы время ее прохождения запускало анимацию на отдельных слоях бликов. Я подумал о создании CAAnimationGroup с 36 анимациями, для каждой из которых задано значение задержки, чтобы они запускались последовательно. Я надеялся, что это может дать мне обратный вызов animationDidStop для каждой анимации. Но документация Apple, похоже, указывает, что вы получаете только один из них для всей группы, а не для каждой анимации в ней. - person quickthyme; 12.05.2011