Я вращаю CALayer и пытаюсь остановить его в конечной позиции после завершения анимации.
Но после завершения анимации он возвращается в исходное положение.
(Документы xcode явно говорят, что анимация не обновляет значение свойства.)
любые предложения, как этого добиться.
ios
iphone
calayer
cabasicanimation
Нилеш Укей
источник
источник
.presentation()
чтобы получить "окончательное, увиденное" значение. Найдите правильные ответы ниже, которые объясняют, что это сделано на уровне представления.Ответы:
Вот ответ, это комбинация моего ответа и ответа Кришнана.
cabasicanimation.fillMode = kCAFillModeForwards; cabasicanimation.removedOnCompletion = NO;
Значение по умолчанию -
kCAFillModeRemoved
. (Какое поведение при сбросе вы видите.)источник
Проблема с removeOnCompletion заключается в том, что элемент пользовательского интерфейса не позволяет взаимодействовать с пользователем.
Метод I заключается в установке значения FROM в анимации и значения TO на объекте. Перед запуском анимация автоматически заполнит значение TO, а после удаления оставит объект в правильном состоянии.
// fade in CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath: @"opacity"]; alphaAnimation.fillMode = kCAFillModeForwards; alphaAnimation.fromValue = NUM_FLOAT(0); self.view.layer.opacity = 1; [self.view.layer addAnimation: alphaAnimation forKey: @"fade"];
источник
alphaAnimation.beginTime = 1;
Кроме того,fillMode
насколько я могу судить, не требуется ...?beginTime
это не относительное понятие, вы должны использовать, например:CACurrentMediaTime()+1;
fillMode
, см. подробнее в разделе « Предотвращение возврата слоев кУстановите следующее свойство:
animationObject.removedOnCompletion = NO;
источник
Вы можете просто установить ключ
CABasicAnimation
на,position
когда добавляете его на слой. Таким образом, он переопределит неявную анимацию, выполненную в позиции для текущего прохода в цикле выполнения.CGFloat yOffset = 30; CGPoint endPosition = CGPointMake(someLayer.position.x,someLayer.position.y + yOffset); someLayer.position = endPosition; // Implicit animation for position CABasicAnimation * animation =[CABasicAnimation animationWithKeyPath:@"position.y"]; animation.fromValue = @(someLayer.position.y); animation.toValue = @(someLayer.position.y + yOffset); [someLayer addAnimation:animation forKey:@"position"]; // The explicit animation 'animation' override implicit animation
Вы можете получить дополнительную информацию о Apple WWDC Video Session 421 2011 - Core Animation Essentials (середина видео)
источник
someLayer.position = endPosition;
. И спасибо за ссылку на WWDC!просто поместите это в свой код
CAAnimationGroup *theGroup = [CAAnimationGroup animation]; theGroup.fillMode = kCAFillModeForwards; theGroup.removedOnCompletion = NO;
источник
CALayer имеет уровень модели и уровень представления. Во время анимации уровень представления обновляется независимо от модели. Когда анимация завершена, уровень представления обновляется значением из модели. Если вы хотите избежать резкого скачка после окончания анимации, главное - синхронизировать два слоя.
Если вы знаете конечное значение, вы можете просто установить модель напрямую.
self.view.layer.opacity = 1;
Но если у вас есть анимация, в которой вы не знаете конечную позицию (например, медленное затухание, которое пользователь может приостановить, а затем повернуть вспять), вы можете напрямую запросить уровень представления, чтобы найти текущее значение, а затем обновить модель.
NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"]; [self.layer setValue:opacity forKeyPath:@"opacity"];
Извлечение значения из уровня представления также особенно полезно для масштабирования или поворота траекторий клавиш. (например
transform.scale
,transform.rotation
)источник
Без использования
removedOnCompletion
Вы можете попробовать эту технику:
self.animateOnX(item: shapeLayer) func animateOnX(item:CAShapeLayer) { let endPostion = CGPoint(x: 200, y: 0) let pathAnimation = CABasicAnimation(keyPath: "position") // pathAnimation.duration = 20 pathAnimation.fromValue = CGPoint(x: 0, y: 0)//comment this line and notice the difference pathAnimation.toValue = endPostion pathAnimation.fillMode = kCAFillModeBoth item.position = endPostion//prevent the CABasicAnimation from resetting item's position when the animation finishes item.add(pathAnimation, forKey: nil) }
источник
Базовая анимация поддерживает две иерархии слоев: уровень модели и уровень представления . Когда анимация выполняется, слой модели фактически не поврежден и сохраняет исходное значение. По умолчанию анимация удаляется после завершения. Затем уровень представления возвращается к значению уровня модели.
Просто установка
removedOnCompletion
сNO
помощью анимации не будет удалена и отходы памяти. Кроме того, уровень модели и уровень представления больше не будут синхронными, что может привести к потенциальным ошибкам.Поэтому было бы лучше обновить свойство прямо на уровне модели до окончательного значения.
self.view.layer.opacity = 1; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; animation.fromValue = 0; animation.toValue = 1; [self.view.layer addAnimation:animation forKey:nil];
Если есть какая-либо неявная анимация, вызванная первой строкой приведенного выше кода, попробуйте отключить ее:
[CATransaction begin]; [CATransaction setDisableActions:YES]; self.view.layer.opacity = 1; [CATransaction commit]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; animation.fromValue = 0; animation.toValue = 1; [self.view.layer addAnimation:animation forKey:nil];
источник
Итак, моя проблема заключалась в том, что я пытался повернуть объект на жесте панорамирования, и поэтому у меня было несколько одинаковых анимаций для каждого движения. У меня было и то,
fillMode = kCAFillModeForwards
и другое,isRemovedOnCompletion = false
но это не помогло. В моем случае я должен был убедиться, что ключ анимации отличается каждый раз, когда я добавляю новую анимацию :let angle = // here is my computed angle let rotate = CABasicAnimation(keyPath: "transform.rotation.z") rotate.toValue = angle rotate.duration = 0.1 rotate.isRemovedOnCompletion = false rotate.fillMode = CAMediaTimingFillMode.forwards head.layer.add(rotate, forKey: "rotate\(angle)")
источник
Это работает:
let animation = CABasicAnimation(keyPath: "opacity") animation.fromValue = 0 animation.toValue = 1 animation.duration = 0.3 someLayer.opacity = 1 // important, this is the state you want visible after the animation finishes. someLayer.addAnimation(animation, forKey: "myAnimation")
Базовая анимация показывает «слой представления» поверх обычного слоя во время анимации. Поэтому установите непрозрачность (или что-то еще) на то, что вы хотите видеть, когда анимация закончится и слой презентации исчезнет. Сделайте это в строке перед добавлением анимации, чтобы избежать мерцания после ее завершения.
Если вы хотите отсрочку, сделайте следующее:
let animation = CABasicAnimation(keyPath: "opacity") animation.fromValue = 0 animation.toValue = 1 animation.duration = 0.3 animation.beginTime = someLayer.convertTime(CACurrentMediaTime(), fromLayer: nil) + 1 animation.fillMode = kCAFillModeBackwards // So the opacity is 0 while the animation waits to start. someLayer.opacity = 1 // <- important, this is the state you want visible after the animation finishes. someLayer.addAnimation(animation, forKey: "myAnimation")
Наконец, если вы используете «removeOnCompletion = false», произойдет утечка CAAnimations, пока слой в конечном итоге не будет удален - избегайте.
источник
Просто установка
fillMode
иremovedOnCompletion
не работала у меня. Я решил проблему, установив все свойства ниже для объекта CABasicAnimation:CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"]; ba.duration = 0.38f; ba.fillMode = kCAFillModeForwards; ba.removedOnCompletion = NO; ba.autoreverses = NO; ba.repeatCount = 0; ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.85f, 0.85f, 1.0f)]; [myView.layer addAnimation:ba forKey:nil];
Этот код трансформируется
myView
до 85% своего размера (3-е измерение без изменений).источник
Ответ @Leslie Godwin не очень хорош: "self.view.layer.opacity = 1;" выполняется немедленно (это занимает около секунды), исправьте alphaAnimation.duration до 10.0, если у вас есть сомнения. Вы должны удалить эту строку.
Итак, когда вы исправляете fillMode на kCAFillModeForwards и removeOnCompletion на NO, вы позволяете анимации оставаться в слое. Если вы исправите делегат анимации и попробуете что-то вроде:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { [theLayer removeAllAnimations]; }
... слой восстанавливается сразу после выполнения этой строки. Этого мы хотели избежать.
Перед удалением анимации необходимо исправить свойство слоя. Попробуй это:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if([anim isKindOfClass:[CABasicAnimation class] ]) // check, because of the cast { CALayer *theLayer = 0; if(anim==[_b1 animationForKey:@"opacity"]) theLayer = _b1; // I have two layers else if(anim==[_b2 animationForKey:@"opacity"]) theLayer = _b2; if(theLayer) { CGFloat toValue = [((CABasicAnimation*)anim).toValue floatValue]; [theLayer setOpacity:toValue]; [theLayer removeAllAnimations]; } } }
источник
Кажется, что для флага removeOnCompletion установлено значение false, а для fillMode установлено значение kCAFillModeForwards. У меня тоже не работает.
После того, как я применил новую анимацию к слою, анимированный объект сбрасывается в исходное состояние, а затем анимируется из этого состояния. Что необходимо сделать дополнительно, так это установить желаемое свойство слоя модели в соответствии со свойством уровня представления перед установкой новой анимации следующим образом:
someLayer.path = ((CAShapeLayer *)[someLayer presentationLayer]).path; [someLayer addAnimation:someAnimation forKey:@"someAnimation"];
источник
Самое простое решение - использовать неявную анимацию. Это решит все эти проблемы за вас:
self.layer?.backgroundColor = NSColor.red.cgColor;
Если вы хотите настроить, например, продолжительность, вы можете использовать
NSAnimationContext
:NSAnimationContext.beginGrouping(); NSAnimationContext.current.duration = 0.5; self.layer?.backgroundColor = NSColor.red.cgColor; NSAnimationContext.endGrouping();
Примечание: это проверено только на macOS.
Я изначально при этом не видел никакой анимации. Проблема в том, что слой слоя с поддержкой просмотра не имеет неявной анимации. Чтобы решить эту проблему, убедитесь, что вы добавили слой самостоятельно (перед тем, как установить вид с поддержкой слоев).
Пример того, как это сделать:
override func awakeFromNib() { self.layer = CALayer(); //self.wantsLayer = true; }
Использование
self.wantsLayer
не имело никакого значения в моем тестировании, но могло иметь некоторые побочные эффекты, о которых я не знаю.источник
Вот образец с детской площадки:
import PlaygroundSupport import UIKit let resultRotation = CGFloat.pi / 2 let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 300.0)) view.backgroundColor = .red //-------------------------------------------------------------------------------- let rotate = CABasicAnimation(keyPath: "transform.rotation.z") // 1 rotate.fromValue = CGFloat.pi / 3 // 2 rotate.toValue = resultRotation // 3 rotate.duration = 5.0 // 4 rotate.beginTime = CACurrentMediaTime() + 1.0 // 5 // rotate.isRemovedOnCompletion = false // 6 rotate.fillMode = .backwards // 7 view.layer.add(rotate, forKey: nil) // 8 view.layer.setAffineTransform(CGAffineTransform(rotationAngle: resultRotation)) // 9 //-------------------------------------------------------------------------------- PlaygroundPage.current.liveView = view
false
чтобыisRemovedOnCompletion
- пусть Core Animation чистой после того , как анимация законченаисточник