动画完成后,CABasicAnimation将重置为初始值

Nil*_*key 132 iphone calayer cabasicanimation ios

我正在旋转CALayer,并在动画完成后尝试将其停在最终位置.

但是在动画完成后,它会重置到其初始位置.

(xcode docs明确表示动画不会更新属性的值.)

任何建议如何实现这一目标.

Nil*_*key 266

编辑:这是答案,这是我的答案和Krishnan的结合.

cabasicanimation.fillMode = kCAFillModeForwards;
cabasicanimation.removedOnCompletion = NO;
Run Code Online (Sandbox Code Playgroud)

默认值为kCAFillModeRemoved.(这是你看到的重置行为.)

  • 这不是正确答案,请参阅@Leslie Godwin的答案. (19认同)
  • 这可能不是正确答案 - 请参阅Krishnan答案的评论.你通常需要这个和Krishnan的; 只是其中一个不起作用. (6认同)
  • @Leslie解决方案更好,因为它将最终值存储在图层中而不是动画中. (6认同)
  • 接受这个作为答案. (3认同)
  • 将removeOnCompletion 设置为NO 时要小心。如果您将动画委托分配给“self”,则动画将保留您的实例。因此,在调用removeFromSuperview后,如果您忘记自己删除/销毁动画,则不会调用dealloc等。你会出现内存泄漏。 (3认同)
  • 这个200多分的答案完全、完全、完全错误。 (2认同)

Les*_*win 80

removedOnCompletion的问题是UI元素不允许用户交互.

我的技术是在动画中设置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"];
Run Code Online (Sandbox Code Playgroud)

  • 如果设置启动延迟,则无效.例如`alphaAnimation.beginTime = 1;`另外,据我所知,不需要`fillMode` ......? (7认同)
  • 正确答案,但不需要`fillMode`,请参阅[防止图层在使用显式CAAnimations时回退到原始值]中的更多信息](http://oleb.net/blog/2012/11/prevent-caanimation-snap-back/ ) (4认同)
  • 我还应该注意`beginTime`不是相对的,你应该使用例如:`CACurrentMediaTime()+ 1;` (2认同)

Kri*_*nan 16

设置以下属性:

animationObject.removedOnCompletion = NO;
Run Code Online (Sandbox Code Playgroud)

  • 我不得不同时使用.fillMode = kCAFillModeForwards和.removedOnCompletion = NO.谢谢! (7认同)

Liz*_* Hu 13

核心动画维护两层层次结构:模型层表现层。当动画正在进行时,模型层实际上是完整的并保持其初始值。默认情况下,动画一旦完成就会被移除。然后表现层回退到模型层的值。

简单地设置removedOnCompletionNO意味着动画不会被删除并浪费内存。此外,模型层和表示层将不再同步,这可能会导致潜在的错误。

所以直接将模型层上的属性更新为最终值会是一个更好的解决方案。

self.view.layer.opacity = 1;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = 0;
animation.toValue = 1;
[self.view.layer addAnimation:animation forKey:nil];
Run Code Online (Sandbox Code Playgroud)

如果上面代码的第一行有任何隐式动画引起的,请尝试将其关闭:

[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];
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你!这确实应该是公认的答案,因为它正确地解释了此功能,而不是仅仅使用创可贴来使其工作 (2认同)

msk*_*mar 12

把它放在你的代码中

CAAnimationGroup *theGroup = [CAAnimationGroup animation];

theGroup.fillMode = kCAFillModeForwards;

theGroup.removedOnCompletion = NO;
Run Code Online (Sandbox Code Playgroud)


sun*_*ejr 12

所以我的问题是我试图在平移手势上旋转一个对象,所以我在每次移动时都有多个相同的动画。我有两个fillMode = kCAFillModeForwardsisRemovedOnCompletion = 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)")
Run Code Online (Sandbox Code Playgroud)


yag*_*eek 11

你可以简单地设置的键CABasicAnimationposition当你把它添加到层.通过这样做,它将覆盖在运行循环中当前传递的位置上完成的隐式动画.

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
Run Code Online (Sandbox Code Playgroud)

您可以获得有关2011 Apple WWDC Video Session 421 - Core Animation Essentials(视频中间)的更多信息

  • 这看起来是这样做的正确方法。动画自然被移除(默认),一旦动画完成,它会返回动画开始之前设置的值,特别是这一行:`someLayer.position = endPosition;`。并感谢对 WWDC 的引用! (2认同)

Chr*_*ris 9

这有效:

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")
Run Code Online (Sandbox Code Playgroud)

核心动画在动画期间在您的普通层之上显示一个“表示层”。因此,将不透明度(或其他)设置为您希望在动画完成且表示层消失时看到的内容。添加动画之前在线上执行此操作,以避免动画完成时出现闪烁。

如果您想延迟,请执行以下操作:

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")
Run Code Online (Sandbox Code Playgroud)

最后,如果您使用 'removedOnCompletion = false' 它会泄漏 CAAnimations 直到该层最终被处置 - 避免。


Jas*_*ore 7

CALayer具有模型层和表示层。在动画期间,表示层独立于模型进行更新。动画完成后,将使用模型中的值更新表示层。如果要避免动画结束后出现跳动,关键是使两个图层保持同步。

如果知道最终值,则可以直接设置模型。

self.view.layer.opacity = 1;
Run Code Online (Sandbox Code Playgroud)

但是,如果您有一个不知道结束位置的动画(例如,用户可以暂停然后反转的缓慢淡入淡出),则可以直接查询表示层以找到当前值,然后更新模型。

NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"];
[self.layer setValue:opacity forKeyPath:@"opacity"];
Run Code Online (Sandbox Code Playgroud)

从表示层提取值对于缩放或旋转关键路径也特别有用。(例如transform.scaletransform.rotation


Pau*_*ros 7

简单的设置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];
Run Code Online (Sandbox Code Playgroud)

此代码转换myView为其大小的85%(第三维未更改).


Aym*_*him 5

不使用 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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎是最佳的答案 (2认同)