Анимация UIView с помощью autoreverse

у меня проблема с настройкой UIViewAnimationOptionAutoReverse. Вот мой код.

CALayer *aniLayer = act.viewToChange.layer;
[UIView animateWithDuration:2.0 delay:1.0 options:(UIViewAnimationCurveLinear | UIViewAnimationOptionAutoreverse) animations:^{
                    viewToAnimate.frame = GCRectMake(1,1,100,100);
                    [aniLayer setValue:[NSNumber numberWithFloat:degreesToRadians(34)] forKeyPath:@"transform.rotation"];
                } completion:nil ];

проблема в том, что после того, как анимация была отменена, представление возвращается к кадру, установленному в блоке анимации. Я не хочу, чтобы расти и "ungrow" и остановится в исходном положении.

есть ли решение без программирования двух последовательных анимаций?

3 ответов


у вас есть три варианта.

при использовании -[UIView animateWithDuration:…] методы, изменения, которые вы делаете в animations блок применяются немедленно к рассматриваемым представлениям. Однако существует также неявное CAAnimation применяется к представлению, которое анимирует от старого значения к новому значению. Когда CAAnimation активен в представлении, он изменяет отображается view, но не изменяет фактические свойства представления.

например, если вы делаете это:

NSLog(@"old center: %@", NSStringFromCGPoint(someView.center));
[UIView animateWithDuration:2.0 animations: ^{ someView.center = newPoint; }];
NSLog(@"new center: %@", NSStringFromCGPoint(someView.center));

вы увидите, что "старый центр" и "новый центр" разные; новый центр будет тут отражают значения newPoint. Однако CAAnimation, что косвенно приводит мнение еще отображается в старом центре и плавно двигаться свой путь в новый центр. Когда анимация завершается, она удаляется из представления, и вы переключаетесь на просмотр фактических значений модели.

когда вы проходите UIViewAnimationOptionAutoreverse, это влияет на неявно создан CAAnimation, но не влияет на фактическое изменение, которое вы делаете для значений. То есть, если бы наш пример выше имел UIViewAnimationOptionAutoreverse определено, затем неявно создано CAAnimation будет анимироваться из oldCenter в newCenter и обратно. Затем анимация будет удалена, и мы вернемся к просмотру значений, которые мы установили... что еще за новая позиция.

Первый Вариант

CGPoint oldCenter = someView.center;
[UIView animateWithDuration:2.0
                 animations: ^{ someView.center = newPoint; }
                 completion: 
   ^(BOOL finished) {
       [UIView animateWithDuration:2.0
                        animations:^{ someView.center = oldCenter; }];
   }];

Второй Вариант

второй вариант состоит в том, чтобы autoreverse анимации, как вы делаете, и установить вид обратно в исходное положение в блоке завершения:

CGPoint oldCenter = someView.center;
[UIView animateWithDuration:2.0
                      delay:0
                    options: UIViewAnimationOptionAutoreverse
                 animations: ^{ someView.center = newPoint; }
                 completion: ^(BOOL finished) { someView.center = oldCenter; }];

тем не менее, это может вызвать мерцание между временем завершения анимации autoreverse и когда блок завершения выполняется, так что это, вероятно, не ваш лучший выбор.

Третий Вариант

последний вариант-просто создать CAAnimation напрямую. Когда вы на самом деле не хотите изменять конечное значение изменяемого свойства, это часто проще.

#import <QuartzCore/QuartzCore.h>

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.autoreverses = YES;
animation.repeatCount = 1; // Play it just once, and then reverse it
animation.toValue = [NSValue valueWithCGPoint:newPoint];
[someView.layer addAnimation:animation forKey:nil];

отметим, что CAAnimation способ делать вещи никогда не изменяет фактические значения вид; оно просто маскирует фактические значения с анимацией. Вид все еще думает, что он в исходном месте. (Это означает, например, что если ваш взгляд реагирует на сенсорные события, он по-прежнему будет наблюдать за этими сенсорными событиями в исходном месте. Анимация только изменяет способ рисования вида; ничего больше.

на CAAnimation путь также требует, чтобы вы добавили его в базовое представление CALayer. Если это пугает вас, не стесняйтесь использовать методы. Существует дополнительная функциональность, доступная с помощью CAAnimation, но если это что-то, с чем вы не знакомы, цепочка UIView анимация или сброс его в блоке завершения вполне приемлемы. На самом деле, это одна из основных целей блока завершения.

Итак, вот ты где. Три разных способа отменить анимацию и сохранить исходное значение. Наслаждайтесь!


вот мое решение. Для 2x повторите, анимируйте 1.5 x и сделайте последнюю часть 0.5 x самостоятельно:

[UIView animateWithDuration:.3
                      delay:.0f
                    options:(UIViewAnimationOptionRepeat|
                             UIViewAnimationOptionAutoreverse)
                 animations:^{
                     [UIView setAnimationRepeatCount:1.5f];

                     ... animate here ...

                 } completion:^(BOOL finished) {
                         [UIView animateWithDuration:.3 animations:^{

                             ... finish the animation here ....

                         }];
                 }];

нет мигания, работает хорошо.


есть repeatCount свойство on CAMediaTiming. Я думаю, вы должны создать явный CAAnimation объект и настройте его правильно. RepeatCount для grow и ungrow будет 2, но вы можете проверить это.

что-то долго ждать этого. Вы бы хоть нужны два объекта CAAnimation, одна для каркаса и для ротации.

CABasicAnimation *theAnimation;

theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
theAnimation.duration=3.0;
theAnimation.repeatCount=1;
theAnimation.autoreverses=YES;
theAnimation.fromValue=[NSNumber numberWithFloat:0.0];
theAnimation.toValue=[NSNumber numberWithFloat:degreesToRadians(34)];
[theLayer addAnimation:theAnimation forKey:@"animateRotation"];

AFAIK нет способа избежать программирования двух объектов анимации.