#ios #core-animation #caanimation
#iOS #ядро-анимация #caanimation
Вопрос:
У меня есть представление, которое я позволяю пульсировать, используя CAAnimation
.
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
animation.values = @[ @0.0f, @1.0f, @0.0f ];
animation.duration = 0.5;
animation.repeatCount = HUGE_VALF;
[view.layer addAnimation:animation forKey:@"pulsate"];
Когда я удаляю анимацию с использованием [view.layer removeAnimationForKey:@"pulsate"]
непрозрачности, она немедленно возвращается. Чего я хотел бы добиться, так это того, что текущая выполняемая пульсирующая анимация завершена, а затем анимация удаляется.
Я попытался, установив значение repeatCount
1, но это вызывает исключение, потому что анимация неизменна.
Также я попытался получить текущее значение из уровня представления и применить его к модели, затем удалить анимацию и снова добавить анимацию для ее завершения. Но это приводит к заметным сбоям при остановке анимации, а также к тому, что время обычно отключается.
Есть ли способ позволить анимации завершить цикл и удалить ее после этого?
Ответ №1:
Нужно разобраться во многих деталях, но общая идея состоит в том, чтобы создать неповторяющуюся анимацию, которая удаляется по завершении, а затем использовать метод animationDidStop
делегирования для перезапуска анимации.
Первым делом необходимо объявить некоторые свойства
@property (weak, nonatomic) IBOutlet UIImageView *orangeView2;
@property (nonatomic) bool pulseActive;
@property (strong, nonatomic) CAKeyframeAnimation *pulseAnimation;
Первое свойство — это представление, которое будет анимировано, второе отслеживает, включена ли анимация, а последнее — фактическая анимация (хранится в property, так что нам нужно создать его экземпляр только один раз).
Далее мы будем использовать отложенное создание экземпляра для создания объекта анимации
- (CAKeyframeAnimation *)pulseAnimation
{
if ( !_pulseAnimation )
{
_pulseAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
_pulseAnimation.values = @[ @0.0f, @1.0f, @0.0f ];
_pulseAnimation.duration = 0.5;
_pulseAnimation.delegate = self;
[_pulseAnimation setValue:@"PulseAnimation" forKey:@"AnimationIdentifier"];
}
return( _pulseAnimation );
}
Важные моменты здесь
- анимация не повторяется (по умолчанию)
- анимация
removedOnCompletion
(по умолчанию) - значение
delegate
установленоself
так, чтоanimationDidStop
будет вызван метод - анимации присваивается идентификатор с помощью
setValue:forKey:
Этот последний элемент необходим только в том случае, если несколько анимаций используют один и тот же делегат, поскольку в этом случае вам понадобится способ определить, какая анимация вызвана animationDidStop
. Строки, передаваемые в forKey
и setValue
, являются произвольными и хранятся в словаре в объекте анимации.
Хорошо, теперь нам нужно реализовать animationDidStop
. Реализация проверяет pulseActive
свойство и при необходимости перезапускает анимацию (после проверки подлинности анимации).
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
NSString *animationIdentifier = [animation valueForKey:@"AnimationIdentifier"];
if ( [animationIdentifier isEqualToString:@"PulseAnimation"] )
{
if ( self.pulseActive )
[self.orangeView2.layer addAnimation:self.pulseAnimation forKey:@"pulsate"];
}
}
Все, что осталось, это запустить и остановить анимацию. Например, кнопка, которая переключает анимацию
- (IBAction)pulseButtonPressed
{
if ( !self.pulseActive )
{
self.pulseActive = YES;
[self.orangeView2.layer addAnimation:[self pulseAnimation] forKey:@"pulsate"];
}
else
{
self.pulseActive = NO;
}
}
Комментарии:
1. Для меня повторное использование анимации не сработало должным образом, однако добавление новой работает отлично. Спасибо!