Objective-C – CABasicAnimation, применяющая изменения после анимации?

Я использую CABasicAnimation для перемещения и изменения размера изображения. Я хочу, чтобы изображение было добавлено в супервизор, анимацию, а затем удалено из супервизора.

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

Проблема в том, что иногда изображение мигает в исходном местоположении перед удалением из супервизора. Каков наилучший способ избежать такого поведения?

 CAAnimationGroup *animGroup = [CAAnimationGroup animation]; animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil]; animGroup.duration = .5; animGroup.delegate = self; [imageView.layer addAnimation:animGroup forKey:nil]; 

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

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

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

Итак, как вы все это делаете? Основной рецепт выглядит так:

 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:myLayer.position]; layer.position = newPosition; // HERE I UPDATE THE MODEL LAYER'S PROPERTY animation.toValue = [NSValue valueWithCGPoint:myLayer.position]; animation.duration = .5; [myLayer addAnimation:animation forKey:animation.keyPath]; 

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

Мне также проще использовать метод +[CATransaction setCompletionBlock:] для установки обработчика завершения для одной или нескольких анимаций вместо того, чтобы пытаться использовать делегат анимации. Вы устанавливаете блок завершения транзакции, затем добавляете анимацию:

 [CATransaction begin]; { [CATransaction setCompletionBlock:^{ [self.imageView removeFromSuperview]; }]; [self addPositionAnimation]; [self addScaleAnimation]; [self addOpacityAnimation]; } [CATransaction commit]; 

CAAnimations автоматически удаляются по завершении. Существует свойство removedOnCompletion которое контролирует это. Вы должны установить это значение NO .

Кроме того, есть что-то известное как fillMode который контролирует поведение анимации до и после его продолжительности. Это свойство объявлено на CAMediaTiming (которое соответствует CAAnimation ). Вы должны установить это для kCAFillModeForwards .

При обоих этих изменениях анимация должна сохраняться после ее завершения. Тем не менее, я не знаю, нужно ли изменять их в группе или в отдельных анимациях внутри группы или в обоих.

Вот пример в Swift, который может помочь кому-то

Это анимация на gradleиентном слое. Это анимирует свойство .locations .

Критическая точка как ответ @robMayoff полностью объясняет, что:

Удивительно, но когда вы делаете анимацию слоя, вы фактически устанавливаете окончательное значение, прежде всего, перед началом анимации!

Следующее – хороший пример, потому что анимация повторяется бесконечно.

Когда анимация повторяется бесконечно, вы иногда увидите «вспышку» между анимациями, если вы сделаете classическую ошибку «забыв установить значение, прежде чем его оживить!».

 var previousLocations: [NSNumber] = [] ... func flexTheColors() { // "flex" the color bands randomly let oldValues = previousTargetLocations let newValues = randomLocations() previousTargetLocations = newValues // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!" theLayer.locations = newValues // AND NOW ANIMATE: CATransaction.begin() // and by the way, this is how you endlessly animate: CATransaction.setCompletionBlock{ [weak self] in if self == nil { return } self?.animeFlexColorsEndless() } let a = CABasicAnimation(keyPath: "locations") a.isCumulative = false a.autoreverses = false a.isRemovedOnCompletion = true a.repeatCount = 0 a.fromValue = oldValues a.toValue = newValues a.duration = (2.0...4.0).random() theLayer.add(a, forKey: nil) CATransaction.commit() } 

Следующее может помочь прояснить что-то для новых программистов. Обратите внимание, что в моем коде я делаю это:

  // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!" theLayer.locations = newValues // AND NOW ANIMATE: CATransaction.begin() ...set up the animation... CATransaction.commit() 

однако в примере кода в другом ответе это выглядит так:

  CATransaction.begin() ...set up the animation... // IN FACT, ACTUALLY "SET THE VALUES, BEFORE ANIMATING!" theLayer.locations = newValues CATransaction.commit() 

Что касается положения строки кода, где вы «задаете значения, перед анимацией!». ..

На самом деле вполне нормально, что эта строка фактически «внутри» строк начала-фиксации кода. Пока вы это делаете до .commit() .

Я только упоминаю об этом, так как это может запутать новых аниматоров.

  • Почему мой преобразуемый атрибут Core Data не использует мой собственный NSValueTransformer?
  • Причина использования ivars против свойств в объекте c
  • Как ограничить длину текста NSTextField и сохранить его всегда в верхнем регистре?
  • Построение часового пояса по часовой стрелке
  • Форматирование номера для отображения запятых и / или знака доллара
  • «FOUNDATION_EXPORT» и «extern»
  • Динамически размер uitableViewCell в соответствии с UILabel (с интервалом между абзацами)
  • Могу ли я локализовать UIDatePicker?
  • Преобразование строки в NSDate
  • UIWebView не изменяет размер при изменении ориентации?
  • Объективные переменные уровня статического classа
  • Interesting Posts

    Вставить текстовый файл в ресурс в собственном приложении Windows

    Когда требуется ключевое слово «typename»?

    Могу ли я использовать встроенный и pci vga одновременно?

    В чем разница между System.Type и System.RuntimeType в C #?

    Как установить MSIE7 в Windows 7?

    Макет в памяти структуры. структура массивов и массив структур в C / C ++

    Веб-сайты Windows Azure переопределяют мои страницы ошибок 404 и 500 в моем приложении node.js

    ASP.NET MVC и аутентификация в смешанном режиме

    Скрипт для изменения содержимого файла в указанных файлах

    Radeon 5500 с монитором Samsung – не получить полный экран?

    Установите Windows 7 на второй жесткий диск после Ubuntu 12.04 … с UEFI

    Ubuntu 9.04, AMD и nVidia: как определить причину блокировки?

    Разделить строку на слова несколькими разделителями

    Куки-файлы на локальном хосте с явным доменом

    Вычисляя расстояние между двумя точками, используя широту долготы, что я делаю неправильно?

    Давайте будем гением компьютера.