Анимация анимации - PullRequest
       28

Анимация анимации

34 голосов
/ 15 декабря 2009

Какой самый элегантный и модульный способ объединения анимации в контексте Core Animation ?

Я имею в виду создание анимации, которая запускается только тогда, когда другие закончили (например, изменение position, а затем opacity). Обычный подход заключается в непосредственном изменении свойств:

layer.position = new_point;
layer.opacity = 0.0f;

но это сделает их одновременно. Я хочу заставить одного ждать другого.

А как насчет анимации цепочки для разных объектов? Я читал о CATransaction используется как:

[CATransaction begin]
layer1.property = new_property;
[CATransaction begin]
layer2.property2 = new_property2;
[CATransaction commit];
[CATransaction commit];

но, похоже, это не работает ..

Ответы [ 6 ]

76 голосов
/ 16 декабря 2009

Вы также можете использовать анимацию группировки и использовать поле beginTime анимации. Попробуйте что-то вроде этого:

CABasicAnimation *posAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
[posAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[posAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[posAnimation setDuration:10.0];
[posAnimation setBeginTime:0.0];

CABasicAnimation *borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[borderWidthAnimation setDuration:10.0];
[borderWidthAnimation setBeginTime:5.0];

CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:10.0];
[group setAnimations:[NSArray arrayWithObjects:posAnimation, borderWidthAnimation, nil]];

[layer addAnimation:group forKey:nil];

Обратите внимание, что продолжительность всей анимации составляет 10 секунд. Первый начинается со второго 0, а второй начинается через 5 секунд.

5 голосов
/ 19 февраля 2013

Как указал Мэтт, вы можете создавать анимационные группы, которые состоят из разных анимаций для одного и того же слоя с разным временем начала. Вы также можете установить делегат для отдельных CAAnimation объектов или CAAnimation групп, и по окончании каждой анимации будет вызываться метод делегата animationDidStop:finished: (обратите внимание, что анимации, являющиеся частью группы, не будут вызывать * делегата их animationDidStop:finished: метод.

Я выяснил классный трюк, который делает использование метода CAAnimation animationDidStop:finished: более мощным. Я использую метод setValue:forKey: для добавления блока кода в отдельную анимацию или группу анимации с помощью клавиши @ "animationCompletionBlock". Затем я пишу общий animationDidStop:finished: метод, который проверяет только что завершенную анимацию для ключа @ "animationCompletionBlock" и, если он ее находит, выполняет там блок кода.

Взгляните на этот проект на github для рабочего примера этой техники:

Демонстрация CAAnimation с блоками завершения

Вы также можете установить группу анимаций внутри

[CATransaction begin];
//...
[[CATransaction commit];

блок, как вы предложили. Когда вы сделаете это, вы можете использовать CATransaction метод класса setCompletionBlock: для вызова блока кода, когда все анимации в текущей группе транзакций завершены. Блок завершения для одной транзакции может затем вызвать следующую транзакцию.

1 голос
/ 14 апреля 2017

Я проверяю это, используя метод setCompletionBlock, чтобы определить замыкание, которое запускает следующую анимацию, когда первая закончена:

[CATransaction begin]
layer1.property = new_property;
CATransaction.setCompletionBlock {
    [CATransaction begin]
    layer2.property2 = new_property2;
    [CATransaction commit];
}
[CATransaction commit];
0 голосов
/ 06 мая 2013

Без включения всех «хитростей» в мою «цепочку инструментов», этот пример не может быть напрямую скопирован / вставлен… но он показывает ДЕЙСТВИТЕЛЬНО простую стратегию для «сцепленной» анимации ..

CATransform3D trans = m34();  // define chain-wide constants.
// Name your "stack". My "nextObject" returns arr[i]->done == nil. 
NSArray *layerStack = layer.sublayers;
//define a block, that "takes" a layer as it's argument.
void(^__block ChainBlock)(CALayer*) = ^(CALayer *m) { 
// animations, transforms, etc for each inividual "step".
    [m animate:@"transform" 
          // These are just NSValue-wrapped CAT3D's
          from:AZV3d(CATransform3DRotate(trans,  0,1,0,0)) 
            to:AZV3d(CATransform3DRotate(trans,1.5,1,0,0)) 
          time:2    // total time == each step * layerStack.count
         eased:kCAMediaTimingFunctionEaseOut
    completion:^{   // In completion, look for "next" layer.
                    CAL*  m2 = [layers nextObject]; 
// If there is "another" layer, call this block, again... with it.
                      if (m2)  chainAnis(m2);
// Otherise,you're done.  Cleanup, toggle values, whatevs.
                     else self.finishedProperty = YES;
    }];
};
// Give the block we just defined your "first" layer.
ChainBlock(layerStack[0]);  // It will recursively feed itself.

Это, очевидно, зависит от некоторой «внешней магии», но концепция проста и устраняет (через зависимости) необходимость «иметь дело» с ЛЮБОЙ разновидностью общего делегирования. В частности, animate:from:to:time:easing:completion и т. д. категории приходят из замечательной FunSize Framework на Github .

0 голосов
/ 19 февраля 2013

То, что я всегда предпочитал устанавливать время начала и окончания каждой анимации отдельно, это:

Я использовал A2DynamicDelegate (разработка которого в настоящее время происходит в BlocksKit -Repo, который знает, почему

Это позволило мне делать такие вещи:

CAAnimation *a = ...
CAAnimation *b = ...
CAAnimation *c = ...

a.completionHandler = ^{
    [self.layer addAnimation:b forKey:@"foo"];
    [self.layer addAnimation:c forKey:@"bar"];
};

Гораздо более гибкий:)

Я загрузил свой код для обработчика завершения здесь . Взгляните на уведомление в заголовочном файле. Я действительно запутался, почему метод не вызывается.

0 голосов
/ 15 декабря 2009

Я не верю, что вы можете "вкладывать" анимации CA, как в вашем примере.

Вам необходимо указать делегат для анимации и поместить свой второй "переход" в селектор animationDidStop:finished: делегата.

Возможно, стоит взглянуть на Apple Руководство по программированию типов анимации и синхронизации .

...