CALayer position animation on video layer - ios

In this tutorial I have found how to make an animation CALayer in video:
http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos
CABasicAnimation *animation
=[CABasicAnimation animationWithKeyPath:#"opacity"];
animation.duration=3.0;
animation.repeatCount=5;
animation.autoreverses=YES;
// animate from fully visible to invisible
animation.fromValue=[NSNumber numberWithFloat:1.0];
animation.toValue=[NSNumber numberWithFloat:0.0];
animation.beginTime = AVCoreAnimationBeginTimeAtZero;
[overlayLayer1 addAnimation:animation forKey:#"animateOpacity"];
But it does not work when I want to animate the movement of CALayer:
animation.keyPath = #"position.x";
or
animation.keyPath = #"position.y";
Is it possible to animate the movement of the CALayer?

Any animations will be interpreted on the video's timeline, not real-time, so you should:
Set animations’ beginTime property to AVCoreAnimationBeginTimeAtZero rather than 0 (which CoreAnimation replaces with CACurrentMediaTime);
Set removedOnCompletion to NO on animations so they are not automatically removed;

Try using this keypath :
animation.keyPath = #"transform.translation.x";

Related

I set the toValue of rotation to 2*PI, but why after the animation these views are not horizontal?

Codes are as follows:
CABasicAnimation *rotateWhenBoom = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotateWhenBoom.fromValue = #0;
rotateWhenBoom.toValue = #(M_PI*2.0);
rotateWhenBoom.duration = 0.3f;
rotateWhenBoom.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
CAAnimationGroup *boom = [CAAnimationGroup animation];
boom.animations = #[[self moveOutWithBtn:btn], rotateWhenBoom];
boom.fillMode = kCAFillModeForwards;
boom.removedOnCompletion = NO;
And the effect:
effect
Before the animation the views are all horizontal. I add a rotation animation to these views, and the toValue of rotation is 2*PI. Why after the animation they are not horizontal?
Thanks in advance!!
Your last two lines of code:
boom.fillMode = kCAFillModeForwards;
boom.removedOnCompletion = NO;
mean that the layer stays at the final state of animation and that the animation is not automatically removed from the layer when it completes. You probably want to remove the last line boom.removeOnCompletion = NO
A good guide for CALayer and CAAnimation that explains this: https://www.objc.io/issues/12-animations/animations-explained/

CoreAnimation - CABasicAnimation get value steps for 30-60 FPS animations

I've got a CABasicAnimation that is operating on the transform property of a CALayer.
The animation looks fairly cool and it all works fine, but now I want to know through which values the transform of the layer is going to go through for a perfect 30/60 FPS animation.
I don't want to run the aniamtion and measure the values, I want to know beforehand.
The timingFunction has to be taken into account for this calculation.
How can I find out these transform values?
That's the animation code:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath: #"transform"];
animation.fromValue = [NSValue valueWithCATransform3D: _myLayer.transform];
animation.toValue = valueTransform;
animation.duration = 0.7;
animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
[_myLayer addAnimation: animation forKey:#"transformAnimation"];

CALayer CABasicAnimation chaining

I'm animating a CALayer's opacity-property with the following code:
Creating the animation in a method:
+ (CABasicAnimation *)fadeIn:(float)begin duration:(float)duration remove:(BOOL)remove{
CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnimation.fromValue = [NSNumber numberWithFloat:0.0];
fadeAnimation.toValue = [NSNumber numberWithFloat:1.0];
fadeAnimation.additive = NO;
fadeAnimation.removedOnCompletion = remove;
fadeAnimation.beginTime = begin;
fadeAnimation.duration = duration;
fadeAnimation.fillMode = kCAFillModeBoth;
return fadeAnimation;
}
Adding the animation to the layer:
[overlayLayer addAnimation:[VideoComposerHelpers fadeIn:1.0 duration:0.5 remove:NO] forKey:nil];
This is working perfect. However, now I want to add another animation to the same layer, right after the first animation finished.
[overlayLayer addAnimation:[VideoComposerHelpers fadeOut:1.5 duration:0.5 remove:NO] forKey:nil]; // fadeOut is a method similar to fadeIn
What should happen is, the layer fades in with a duration of 0.5 and right after that, it fades out with a duration of 0.5.
This doesn't seem to work, though. Is it because the start point of the second animation is the same as the end point of the first one?
You should use a CAAnimationGroup something like this:
CABasicAnimation *fadeIn = [VideoComposerHelpers fadeIn:1.0 duration:0.5 remove:NO];
CABasicAnimation *fadeOut = [VideoComposerHelpers fadeOut:1.5 duration:0.5 remove:NO];
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[group setAnimations:[NSArray arrayWithObjects:fadeIn, fadeOut, nil]];
group.duration = 2;
[overlayLayer addAnimation:group forKey:#"savingAnimation"];
Also I'm not sure if I get the right values vor start, end, duration of the animations (you should check them) :)).
A CABasicAnimation can have a delegate. The delegate will be sent animationDidStop:finished:. Now you can ask for the next animation in the chain.
In your case, though, you don't even need that; just use an animation where autoreverses is YES.
(Oh, and do not mess with removedOnCompletion and fillMode; that's just wrong, and examples that use them are equally wrong. They are needed only in the middle complex grouped animations.)

how to use set layer value automatically when use explicit animation?

I can animately move a layer like this:
CABasicAnimation *animation = [CABasicAnimation animation];
[animation setFromValue:[NSValue valueWithCGPoint:self.layer.position]];
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(100, 100)]];
[self.layer addAnimation:animation forKey:#"position"];
self.layer.position = CGPointMake(100, 100);
however, I have to set the layer.position after the end of animation, is there a way to set it automatically when using explicit animation?
According to the Apple documentation, you have to set it manually :
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html#//apple_ref/doc/uid/TP40004514-CH3-SW3
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 1.0;
[theLayer addAnimation:fadeAnim forKey:#"opacity"];
// Change the actual data value in the layer to the final value.
theLayer.opacity = 0.0;
Unlike an implicit animation, which updates the layer object’s data value, an explicit animation does not modify the data in the layer tree. Explicit animations only produce the animations. At the end of the animation, Core Animation removes the animation object from the layer and redraws the layer using its current data values. If you want the changes from an explicit animation to be permanent, you must also update the layer’s property as shown in the preceding example.

Animate drawing the fill of a CAShapeLayer

I've been playing around with drawing a path using a CAShapeLayer as outlined in this great article, http://oleb.net/blog/2010/12/animating-drawing-of-cgpath-with-cashapelayer, but I'm wondering if there's a way to animate the filling of a layer.
For example, I have some text I want to draw on the screen, but I've only been able to draw the stroke of the text and not the fill. Another example, I have a star shape that I would like to animate it being filled in.
Is this possible using a CAShapeLayer or other object?
Thanks!
Its most of the time the same code, you just have to set different values for fromValue and toValue of your CABasicAnimation. I created a category which returns me a CABasicAnimation:
Animation for StrokeEnd
+ (CABasicAnimation *)animStrokeEndWithDuration:(CGFloat)dur
delegate:(id)target{
CABasicAnimation *animLine =
[CABasicAnimation animationWithKeyPath:#"strokeEnd"];
[animLine setDuration:dur];
[animLine setFromValue:[NSNumber numberWithFloat:0.0f]];
[animLine setToValue:[NSNumber numberWithFloat:1.0f]];
[animLine setRemovedOnCompletion:NO];
[animLine setFillMode:kCAFillModeBoth];
[animLine setDelegate:target];
[animLine setTimingFunction:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
return animLine;
}
Animation for fillColor
+ (CABasicAnimation *)animFillColorWithDur:(CGFloat)dur
startCol:(UIColor *)start
endColor:(UIColor *)end
delegate:(id)target{
CABasicAnimation *animFill =
[CABasicAnimation animationWithKeyPath:#"fillColor"];
[animFill setDuration:dur];
[animFill setFromValue:(id)start.CGColor];
[animFill setToValue:(id)end.CGColor];
[animFill setRemovedOnCompletion:NO];
[animFill setDelegate:target];
[animFill setFillMode:kCAFillModeBoth];
return animFill;
}
The returned CABasicAnimation just has to be added to a CAShapeLayer:
[_myShapeLayer addAnimation:returnedAnimation forKey:#"animKey"]
Yes, it is possible.
CAShapeLayers have a fillColor property which is animatable.
It works the same way as changing the strokeEnd / strokeStart like you've already done with with your animation.

Resources