CAKeyframeAnimation repeat animation from begin to end - ios

I need to add infinite animation for UIImageView from start point to end point and after that from end point to start point.
I am trying like this:
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.duration = 2.0;
pathAnimation.repeatCount = HUGE_VALF;
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CGPoint endPoint = CGPointMake(320.0f - 30.0f, self.myImage.frame.size.height);
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, self.myImage.frame.origin.x, self.myImage.frame.origin.y);
CGPathAddCurveToPoint(curvedPath, NULL, endPoint.x, self.myImage.frame.origin.y,
endPoint.x, self.myImage.frame.origin.y, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
[self.myImage.layer addAnimation:pathAnimation forKey:#"curveAnimation"];
myImage moves from start point to end ok, but after that move to start point and repeat animation from start point to end. So, There is no animation from end point to start. Is it possible to do?

Animating back the same way as you came is as simple as setting autoreverses to YES.
That said, If it's truly an infinite animation then you don't need the fillMode or the removedOnCompletion

I were you, I'd simply use :
[UIVIew animateWithDuration:delay:options:animations:completion:]
with the options
UIViewAnimationOptionRepeat

Related

IOS current keyframe y axis

Hey im trying to show the y axis of my imageview while its moving , but its not displaying the animating y axis , its showing only one number .
//LINE ANAMATION
CALayer *layer = line.layer;
CGPoint startPoint = (CGPoint){line.center.x,20};
CGPoint endPoint = (CGPoint){line.center.x, screenSizeY/2};
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, NULL, startPoint.x, startPoint.y);
CGPathAddLineToPoint(thePath, NULL, endPoint.x, endPoint.y);
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.duration = 3.f;
animation.path = thePath;
animation.autoreverses = YES;
animation.repeatCount = INFINITY;
[layer addAnimation:animation forKey:#"position"];
NSLog(#"%f", line.center.y);
There are a couple of things wrong with this. First, the animation state is maintained in the presentation layer. Your view and underlying layer are will reflect the final state of the animation immediately. Second, your NSLog statement will only be called once because you aren't in a loop.
If you want to do something at each frame of an animation, you can use CADisplayLink to get a callback on each frame. In this callback, you can check the current Y position by looking at the presentation layer:
- (void)myCallback:(CADisplayLink *)link
{
NSLog(#"%f", CGRectGetMidY(line.layer.presentationLayer.frame));
}

IOS Animated Imageview intercepts another image

So im new to objective-c and i have a image that's moving up and down the screen at all times , how would i code if another image touches or intercepts that image . this is the animation code i have done , but still confused on how to write the second part. thank you for your help
Animation:
//LINE ANAMATION
layer = line.layer;
CGPoint startPoint = (CGPoint){line.center.x,20};
CGPoint endPoint = (CGPoint){line.center.x, screenSizeY/2};
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, NULL, startPoint.x, startPoint.y);
CGPathAddLineToPoint(thePath, NULL, endPoint.x, endPoint.y);
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.duration = 3.f;
animation.path = thePath;
animation.autoreverses = YES;
animation.repeatCount = INFINITY;
[layer addAnimation:animation forKey:#"position"];
Try:
if (CGRectIntersectsRect(self.imageView1.frame, self.imageView2.frame))
{
NSLog(#"Intersected!");
}
else
{
NSLog(#"No intersection :(");
}

How can I know current animation in CAAnimationGroups?

Now I want to use Core Animation to write some methods for animation just as easy as Cocos2d ,just like ccMove,ccFade,ccRotate.
Everything seems ok, but when I want to implement the animation sequence,I've troubled.The first thing I've thought was CCAnimationGroup,but when animations in groups,I can not kown when the current action complete, so I can't set the property of layer, this lead to the layer back to the original status. Anyone know this ? My code:
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
testView.backgroundColor= [UIColor redColor];
testView.center = self.view.center;
//mark1: textview's position is self.view.center
[self.view addSubview:testView];
CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation
animationWithKeyPath:#"position"];
moveAnimation.duration = 3;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 100, 100);
CGPathAddLineToPoint(path, NULL, 200, 200);
moveAnimation.path = path;
//mark2: I want the testview move to CGPointMake(100,200)
CGPathRelease(path);
CABasicAnimation *angleAnimation =
[CABasicAnimation
animationWithKeyPath:#"transform.rotation"];
angleAnimation.toValue = #(45 * M_PI / 180);
angleAnimation.duration = 3;
angleAnimation.beginTime = 3; //make3: rotate testview 45°
CAAnimationGroup *actionGroup = [CAAnimationGroup animation];
[actionGroup setDuration:6];
[actionGroup setAnimations:#[moveAnimation, angleAnimation]];
[CATransaction begin];
[testView.layer addAnimation:actionGroup forKey:nil];
[CATransaction commit];
You can run it, and you'll see the textview's position and rotate is not I want.
Can someone help me?
I've solved it.In fact,I don't need to know when one of the actions in group complete.Just set the animation's fillMode and removedOnCompletion, so that the the layer would not back to original status.
UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
testView.backgroundColor= [UIColor redColor];
testView.center = self.view.center;
[self.view addSubview:testView]; //mark1: textview's position is self.view.center
CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
moveAnimation.duration = 3;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 100, 100);
CGPathAddLineToPoint(path, NULL, 200, 200);
moveAnimation.path = path;
moveAnimation.fillMode = kCAFillModeForwards;
moveAnimation.removedOnCompletion = NO;
CGPathRelease(path); //mark2: I want the testview move to CGPointMake(100,200)
CABasicAnimation *angleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
angleAnimation.toValue = #(45 * M_PI / 180);
angleAnimation.duration = 3;
angleAnimation.beginTime = 3; //make3: rotate testview 45°
angleAnimation.fillMode = kCAFillModeForwards;
angleAnimation.removedOnCompletion = NO;
CAAnimationGroup *actionGroup = [CAAnimationGroup animation];
[actionGroup setDuration:6];
[actionGroup setAnimations:#[moveAnimation, angleAnimation]];
actionGroup.fillMode = kCAFillModeForwards;
actionGroup.removedOnCompletion = NO;
[CATransaction begin];
[testView.layer addAnimation:actionGroup forKey:nil];
[CATransaction commit];
In code above, I set all the action's fillmode to kCAFillModeForwards, and removedOnCompletion = NO.This just work. And I also find that scaleAnimation and fadeAnimation should set their fillmode to kCAFillModeBoth so that the layer cannot back to original property status.
You can also check the code on my github.https://github.com/Vienta/SSAnimation Thank you!
CAAnimationGroup is subclass of CAAnimation, so you can have a delegate of CAAnimationGroup and receive notification when animation stoped.
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

CALayer setPosition not called during animation

I have a custom CALayer that I am animating using a CAAnimationGroup to follow a path and rotate at a tangent to the path:
// Create the animation path
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
//Setting Endpoint of the animation
CGRect contentBounds = [self contentBounds];
self.boatLayer.bounds = contentBounds;
CGPoint endPoint = CGPointMake(contentBounds.size.width - 150, contentBounds.size.height - 150);
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, startPosition.x, startPosition.y);
CGPathAddCurveToPoint(curvedPath, NULL, endPoint.x, 0, endPoint.x, 0, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
pathAnimation.duration = 10.0;
pathAnimation.rotationMode = kCAAnimationRotateAuto;
pathAnimation.delegate = self;
// Create an animation group of all the animations
CAAnimationGroup *animationGroup = [[[CAAnimationGroup alloc] init] autorelease];
animationGroup.animations = [NSArray arrayWithObjects:pathAnimation, nil];
animationGroup.duration = 10.0;
animationGroup.removedOnCompletion = NO;
// Add the animations group to the layer (this starts the animation at the next refresh cycle)
[testLayer addAnimation:animationGroup forKey:#"animation"];
I need to be able to track the changes to the position and rotation of the layer as it progresses along the path. I have overridden both setPosition and setTransform (calling super setPosition and super setTranform) and then logging their values. Neither of these values appear to be set during the animation.
How can I get the position and rotation updates from within the CALayer class itself as it animates?
Core Animation doesn't work like that
Sorry. That is not how Core Animation work. When you add an animation to a layer it doesn't change the model of that layer. Only the presentation.
When you configure then animation to not remove itself upon completion
yourAnimation.fillMode = kCAFillModeForwards;
tourAnimation.removedOnCompletion = NO;
you are actually causing an inconsistency between what is shown on screen and the model of that layer. If you for instance had a button that you animated like this you would get very surprised/angry by the fact that it "no longer responds to toucher" or even more funny "responds to touches from it's 'old' location".
Semi-solutions
Depending on what and how often you actually need the updates you could either periodically check the value of the presentationLayer during the animation or use a CADisplayLink to run some code when the screen changes.

Animation along path - Completion method called too early

I'd like to implement an animation along a rounded path and fire a completion function as soon as the animation has ended.
Thanks to this post I figured out how to use a CAKeyframeAnimation with a CGMutablePathRef to perform the animation along a path.
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.duration = 1.0;
CGPoint endPoint = CGPointMake(self.boardReference.view.bounds.size.width/2,self.boardReference.view.bounds.size.height/2);
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, self.view.center.x, self.view.center.y);
CGPathAddCurveToPoint(curvedPath, NULL, endPoint.x, self.view.center.y, endPoint.x, self.view.center.y, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
[self.view.layer addAnimation:pathAnimation forKey:#"curvedPath"];
[self addNewCardAtPoint:endPoint]; //This should only be launched after the animation has been finished
Problem: My method addNewCardAtPoint should only be called after the animation has been completed. Currently the process is not blocking so the method is called more or less simultaneously.
At the first view the animateWithDuration function seems to better suited as it has defined blocks for the animation and the completion action. But simply adding the CAKeyframeAnimation to the animations block has basically the same result, immediate execution of the completion block.
[UIView animateWithDuration:0.8
animations:^{
NSLog(#"-Animate on curved path to end point-");
... //how perform the same path based animation here?
} completion:^(BOOL finished) {
[self addNewCardAtPoint:self.view.center];
}
];
How can I fire a complete function only after the animation along the curved path has been completed?
When a CAAnimation is done, it will call the animationDidStop:finished: method on its delegate.

Resources