试图通过3秒钟延迟CABasicAnimation位置和层的不透明度,但是(Trying to de

2019-08-08 20:06发布

我试图用setBeginTime 3秒延迟层的不透明度和位置的动画。 我已经叫层boxLayer。 前3秒钟内的动画顺利然而(该层是不应该显示还)在它的最终位置和不透明度显示层。 它不应该。 组动画不能解决问题。 谁能帮助吗? 请参见下面的代码:

// Create an animation that will change the opacity of a layer
CABasicAnimation *fader = [CABasicAnimation animationWithKeyPath:@"opacity"];


// It will last 1 second and will be delayed by 3 seconds
[fader setDuration:1.0];
[fader setBeginTime:CACurrentMediaTime()+3.0];


// The layer's opacity will start at 0.0 (completely transparent)
[fader setFromValue:[NSNumber numberWithFloat:startOpacity]];

// And the layer will end at 1.0 (completely opaque)
[fader setToValue:[NSNumber numberWithFloat:endOpacity]];

// Add it to the layer
[boxLayer addAnimation:fader forKey:@"BigFade"];

// Maintain opacity to 1.0 JUST TO MAKE SURE IT DOES NOT GO BACK TO ORIGINAL OPACITY
[boxLayer setOpacity:endOpacity];


// Create an animation that will change the position of a layer
CABasicAnimation *mover = [CABasicAnimation animationWithKeyPath:@"position"];

// It will last 1 second and will be delayed by 3 seconds
[mover setDuration:1.0];
[mover setBeginTime:CACurrentMediaTime()+3.0];

// Setting starting position
[mover setFromValue:[NSValue valueWithCGPoint:CGPointMake(startX, startY)]];

// Setting ending position
[mover setToValue:[NSValue valueWithCGPoint:CGPointMake(endX, endY)]];

// Add it to the layer
[boxLayer addAnimation:mover forKey:@"BigMove"];

// Maintain the end position at 400.0 450.0 OTHERWISE IT IS GOING BACK TO ORIGINAL POSITION
[boxLayer setPosition:CGPointMake(endX, endY)];

Answer 1:

问题是,你设置boxLayer的性质positionopacity ,以他们的最终值。 你需要:

  1. 设置boxLayer属性的初始值,而不是他们的结局值(这就是为什么它开始的结束位置/阻...通常如果动画立即开始,这不是一个问题,而是因为你推迟启动使用结束位置是有问题的);

  2. 为了您的两个动画,你必须改变removedOnCompletionNOfillModekCAFillModeForwards (这是为了防止其恢复到完成时的原始位置的正确方法)。

从而:

// Create an animation that will change the opacity of a layer
CABasicAnimation *fader = [CABasicAnimation animationWithKeyPath:@"opacity"];

// It will last 1 second and will be delayed by 3 seconds
[fader setDuration:1.0];
[fader setBeginTime:CACurrentMediaTime()+3.0];

// The layer's opacity will start at 0.0 (completely transparent)
[fader setFromValue:[NSNumber numberWithFloat:startOpacity]];

// And the layer will end at 1.0 (completely opaque)
[fader setToValue:[NSNumber numberWithFloat:endOpacity]];

// MAKE SURE IT DOESN'T CHANGE OPACITY BACK TO STARTING VALUE    
[fader setRemovedOnCompletion:NO];
[fader setFillMode:kCAFillModeForwards];

// Add it to the layer
[boxLayer addAnimation:fader forKey:@"BigFade"];

// SET THE OPACITY TO THE STARTING VALUE
[boxLayer setOpacity:startOpacity];

// Create an animation that will change the position of a layer
CABasicAnimation *mover = [CABasicAnimation animationWithKeyPath:@"position"];

// It will last 1 second and will be delayed by 3 seconds
[mover setDuration:1.0];
[mover setBeginTime:CACurrentMediaTime()+3.0];

// Setting starting position
[mover setFromValue:[NSValue valueWithCGPoint:CGPointMake(startX, startY)]];

// Setting ending position
[mover setToValue:[NSValue valueWithCGPoint:CGPointMake(endX, endY)]];

// MAKE SURE IT DOESN'T MOVE BACK TO STARTING POSITION   
[mover setRemovedOnCompletion:NO];
[mover setFillMode:kCAFillModeForwards];

// Add it to the layer
[boxLayer addAnimation:mover forKey:@"BigMove"];

// SET THE POSITION TO THE STARTING POSITION
[boxLayer setPosition:CGPointMake(startX, startY)];

就个人而言,我认为你做的东西,与基于块的动画做了更方便地对视了很多工作,(对于此演示的目的,我假设你boxLayerCALayer一个控件调用box ) 。 你不需要石英2D,或者说,如果你这样做是这样的:

box.alpha = startOpacity;
box.frame = CGRectMake(startX, startY, box.frame.size.width, box.frame.size.height);

[UIView animateWithDuration:1.0
                      delay:3.0
                    options:0
                 animations:^{
                     box.alpha = endOpacity;
                     box.frame = CGRectMake(endX, endY, box.frame.size.width, box.frame.size.height);
                 }
                 completion:nil];


Answer 2:

对于使用beginTime你应该让你的动画对象的必要配置,并设置fillModekCAFillModeBackwards

zoomAnimation.fillMode = kCAFillModeBackwards;

这是苹果文档中说:

使用BEGINTIME属性设置动画的开始时间。 通常情况下,在下一个更新周期中的动画开始。 您可以使用BEGINTIME参数几秒延迟动画的开始时间。 顺便链中的两个动画一起是设置一个动画的开始时间相匹配的其他动画的结束时间。 如果延误动画的开始,你可能还需要设置在fillMode属性kCAFillModeBackwards。 此填充模式使得显示动画的开始值,即使在层树中的层对象包含一个不同的值的层。 如果没有这种填充模式,你会看到一个跳转到终值动画开始执行之前。 其他填充模式可供选择了。

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/AdvancedAnimationTricks/AdvancedAnimationTricks.html#//apple_ref/doc/uid/TP40004514-CH8-SW2

此外,从罗布的问题:

为了您的两个动画,你必须改变removedOnCompletion NO和在fillMode到kCAFillModeForwards(这是为了防止其恢复到完成时的原始位置的正确方法)。

这是一种有争议的说法,这是因为:

一旦动画被删除,表示层将回落到模型层的值,因为我们从来没有修改过的层的位置,我们的飞船再次出现右的地方开始。 有两种方法来解决这个问题:

第一种方法是直接在模型层上更新属性。 这是推荐的方法,因为它使动画完全是可选的。

或者,你可以告诉动画通过其在fillMode属性设置为kCAFillModeForwards保持在其最后的状态,防止它通过设置removedOnCompletion为NO被自动删除。 然而,这是一个很好的做法,保持模型和表示层同步, 所以此方法应谨慎使用

从https://www.objc.io/issues/12-animations/animations-explained/



Answer 3:

这篇文章解释了为什么好,你不应该在fillMode使用removedOnCompletion https://www.objc.io/issues/12-animations/animations-explained/

在我的情况下,我动画的视图,其用作导航但延迟跳出的动画是视图内的层; 我同时需要更新的图层这些位置,因为它可以被排除,然后再次显示。 使用removedOnCompletion一旦动画完成将不会更新层的价值

我这样做的方式是在完成CATransaction块更新层

CATransaction.setCompletionBlock { 
     // update the layer value
 }

CATransaction.begin()

// setup and add your animation

CATransaction.commit()


文章来源: Trying to delay CABasicAnimation position and opacity of layer by 3 seconds but