ios 动画完成后 CABasicAnimation 重置为初始值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6059054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CABasicAnimation resets to initial value after animation completes
提问by Nilesh Ukey
I am rotating a CALayer and trying to stop it at its final position after animation is completed.
我正在旋转 CALayer 并尝试在动画完成后将其停在最终位置。
But after animation completes it resets to its initial position.
但是在动画完成后它会重置到它的初始位置。
(xcode docs explicitly say that the animation will not update the value of the property.)
(xcode 文档明确表示动画不会更新属性的值。)
any suggestions how to achieve this.
如何实现这一目标的任何建议。
回答by Nilesh Ukey
Here's the answer, it's a combination of my answer and Krishnan's.
这是答案,它是我的答案和 Krishnan 的组合。
cabasicanimation.fillMode = kCAFillModeForwards;
cabasicanimation.removedOnCompletion = NO;
The default value is kCAFillModeRemoved
. (Which is the reset behavior you're seeing.)
默认值为kCAFillModeRemoved
。(这是您看到的重置行为。)
回答by Leslie Godwin
The problem with removedOnCompletion is the UI element does not allow user interaction.
RemoveOnCompletion 的问题是 UI 元素不允许用户交互。
I technique is to set the FROM value in the animation and the TO value on the object. The animation will auto fill the TO value before it starts, and when it's removed will leave the object at it's correct state.
我的技术是设置动画中的 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"];
回答by Krishnan
Set the following property:
设置以下属性:
animationObject.removedOnCompletion = NO;
回答by msk_sureshkumar
just put it inside your code
把它放在你的代码中
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.fillMode = kCAFillModeForwards;
theGroup.removedOnCompletion = NO;
回答by yageek
You can simply set the key of CABasicAnimation
to position
when you add it to the layer. By doing this, it will override implicit animation done on the position for the current pass in the run loop.
你可以简单地设置的键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
You can have more information on 2011 Apple WWDC Video Session 421 - Core Animation Essentials (middle of the video)
您可以在 2011 Apple WWDC Video Session 421 - Core Animation Essentials 上获得更多信息(视频中间)
回答by Jason Moore
A CALayer has a model layer and a presentation layer. During an animation, the presentation layer updates independently of the model. When the animation is complete, the presentation layer is updated with the value from the model. If you want to avoid a jarring jump after the animation ends, the key is to keep the two layers in sync.
CALayer 具有模型层和表示层。在动画期间,表示层的更新独立于模型。动画完成后,表示层会使用模型中的值进行更新。如果要避免动画结束后出现刺耳的跳跃,关键是要保持两层同步。
If you know the end value, you can just set the model directly.
如果您知道最终值,则可以直接设置模型。
self.view.layer.opacity = 1;
But if you have an animation where you don't know the end position (e.g. a slow fade that the user can pause and then reverse), then you can query the presentation layer directly to find the current value, and then update the model.
但是如果你有一个不知道结束位置的动画(例如用户可以暂停然后反转的缓慢淡入淡出),那么你可以直接查询表示层以找到当前值,然后更新模型。
NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"];
[self.layer setValue:opacity forKeyPath:@"opacity"];
Pulling the value from the presentation layer is also particularly useful for scaling or rotation keypaths. (e.g. transform.scale
, transform.rotation
)
从表示层中提取值对于缩放或旋转关键路径也特别有用。(例如transform.scale
, transform.rotation
)
回答by Paula Vasconcelos Gueiros
Simply setting fillMode
and removedOnCompletion
didn't work for me. I solved the problem by setting allof the properties below to the CABasicAnimation object:
只是设置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];
This code transforms myView
to 85% of its size (3rd dimension unaltered).
此代码转换myView
为其大小的 85%(第三维不变)。
回答by Ayman Ibrahim
Without using the removedOnCompletion
不使用 removedOnCompletion
You can try this technique:
你可以试试这个技巧:
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)
}
回答by sunshinejr
So my problem was that I was trying to rotate an object on pan gesture and so I had multiple identical animations on each move. I had both fillMode = kCAFillModeForwards
and isRemovedOnCompletion = false
but it didn't help. In my case, I had to make sure that the animation key is different each time I add a new animation:
所以我的问题是我试图在平移手势上旋转一个对象,所以我在每次移动时都有多个相同的动画。我有两个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)")
回答by Lizhen Hu
Core animation maintains two layer hierarchies: the model layerand the presentation layer. When the animation is in progress, the model layer is actually intact and keeps it initial value. By default, the animation is removed once the it's completed. Then the presentation layer falls back to the value of the model layer.
核心动画维护两层层次结构:模型层和表现层。当动画正在进行时,模型层实际上是完整的并保持其初始值。默认情况下,动画一旦完成就会被移除。然后表现层回退到模型层的值。
Simply setting removedOnCompletion
to NO
means the animation won't be removed and wastes memory. In addition, the model layer and the presentation layer won't be synchronous any more, which may lead to potential bugs.
简单地设置removedOnCompletion
为NO
意味着动画不会被删除并浪费内存。此外,模型层和表示层将不再同步,这可能会导致潜在的错误。
So it would be a better solution to update the property directly on the model layer to the final value.
所以直接将模型层上的属性更新为最终值会是一个更好的解决方案。
self.view.layer.opacity = 1;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = 0;
animation.toValue = 1;
[self.view.layer addAnimation:animation forKey:nil];
If there's any implicit animation caused by the first line of above code, try to turn if off:
如果上面代码的第一行有任何隐式动画引起的,请尝试将其关闭:
[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];
- Reference:
- Animations Explainedby objc.io.
- "iOS 7 Programming Pushing the Limits"by Rob Napier and Mugunth Kumar.
- 参考:
- 由 objc.io解释的动画。
- Rob Napier 和 Mugunth Kumar 的“iOS 7 Programming Pushing the Limits”。