Цель-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];
3 ответа:
при добавлении анимации в слой, анимация не изменяет свойства слоя. Вместо этого, система создает копию слоя. Исходный слой называется слоем модели,а дубликат-слоем представления. Свойства слоя представления изменяются по мере развития анимации, но свойства слоя модели остаются неизменными.
при удалении анимации система уничтожает слой представления, оставляя только слой модели, и затем Свойства слоя модели управляют тем, как слой рисуется. Таким образом, если свойства слоя модели не совпадают с окончательными анимированными значениями свойств слоя представления, слой мгновенно сбрасывается до своего внешнего вида перед анимацией.
чтобы исправить это, вам нужно установить свойства слоя модели на конечные значения анимации и затем добавить анимацию в слой. Вы хотите сделать это в таком порядке, потому что изменение свойства слоя может добавить подразумевается анимация для свойства, которое будет конфликтовать с анимацией, которую вы хотите явно добавить. Вы хотите убедиться, что ваша явная анимация переопределяет неявную анимацию.
Так как же вы все это делаете? Основной рецепт выглядит так:
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, который может помочь кому-то
это анимация на градиентном слое. Это анимация
.locations
собственность.критическая точка, как @robMayoff ответ объясняет полностью это:
Удивительно, но когда вы делаете анимацию слоя, вы фактически устанавливаете конечное значение, во-первых, прежде чем начать анимацию!
ниже приведен хороший пример, потому что анимация повторяется бесконечно.
для анимации повторяется бесконечно, вы будете видеть иногда " вспышку "между анимациями, если вы сделаете классическую ошибку" забыв установить значение, прежде чем анимировать его!"
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()
.Я только упоминаю об этом, так как это может запутать новых аниматоров.