iPhone - How to make a circle path for a CAKeyframeAnimation? - iphone

I'm trying to make an key frame animation that lets a image view fly around a circle. I'm using CGPathAddCurveToPoint to make the key frame points. The problem is that the image view always uses the shortest (linear) route.
I would like to have some kind of function that builds a circle path for a given radius.
Thanks a lot for any help.

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
CGPathAddQuadCurveToPoint(path, NULL,middlePoint.x, middlePoint.y,endPoint.x,endPoint.y);
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.removedOnCompletion = NO;
pathAnimation.path = path;
[pathAnimation setCalculationMode:kCAAnimationCubic];
[pathAnimation setFillMode:kCAFillModeForwards];
pathAnimation.duration = 2.0;
[viewTobemoved.layer addAnimation:pathAnimation forKey:nil];
This animation uses only one bezier point and makes a soft circle from beginning point to end point.If you want to define the curve exactly by also defining the radius of the circle you can refer to the following link
http://blog.shoguniphicus.com/2011/05/19/keyframe-animation-ios-cakeyframeanimation-objective-c/

Would this do the trick?
CAKeyframeAnimation* circlePathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"center"];
CGMutablePathRef circularPath = CGPathCreateMutable();
CGRect pathRect = ...; // some rect you define. A circle has equal width/height; radius is half the values you specify here
CGPathAddEllipseInRect(circularPath, NULL, pathRect);
spinAnimation.path = circularPath;
CGPathRelease(circularPath);
You will notice the keypath of the animation is the center property of the UIView you wish to make fly around in a circle.

Related

Gradually Decrease CAShapeLayer wrt radius

I have a UIImageView with image just like above so what i have to do is gradually decrease and increase the shape of the image.
For achieving above task obviously I have to apply mask so I have created a rounded CAShapeLayer and added to the UIImageView layer and its working fine if I change my radius it will show only that amount of image wrt radius.
My problem is how we can apply animation so it will show in animated form. Please guide me I am not able to achieve with keyframe animation.
Following are the code for masking wrt radius.
// Set up the shape of the circle
int rChange = 0; // Its doing proper masking while changing this value
int radius = 123.5-rChange;
CAShapeLayer *circle = [CAShapeLayer layer];
// Make a circular shape
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0+rChange, 0+rChange, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
// Configure the apperence of the circle
[circle setFillColor:[[UIColor blackColor] CGColor]];
[[self.originalImageView layer] setMask:circle];
self.originalImageView.layer.masksToBounds = YES;
where 123.5 is my maximum radius of the image
and originalImageView is myUIImageView
If all you want to do is show a brown circle with an animated varying radius, I suggest two changes:
Don't bother with an image. Just use a CAShapeLayer and set its fillColor to brown.
Set the layer's path once, to a circle with width and height of 1 point. Then use the CAShapeLayer's transform to vary the size. You can animate the transform.
For example, create the layer like this:
CGRect bounds = self.view.bounds;
circleLayer = [CAShapeLayer layer];
circleLayer.fillColor = [UIColor brownColor].CGColor;
    circleLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
// Create a circle with 1-point width/height.
circleLayer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 1, 1)].CGPath;
// Use the layer transform to scale the circle up to the size of the view.
[circleLayer setValue:#(bounds.size.width) forKeyPath:#"transform.scale"];
Then you can change its size like this:
[circleLayer setValue:#(newSize) forKeyPath:#"transform.scale"];
That will implicitly (automatically) animate the size change using default parameters. If you want to use different animation parameters, you can explicitly animate the transform:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
animation.fromValue = [circleLayer valueForKeyPath:#"transform.scale"];
animation.toValue = #(newSize);
animation.duration = 3.0;
animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
// Important: change the actual layer property before installing the animation.
[circleLayer setValue:animation.toValue forKeyPath:animation.keyPath];
// Now install the explicit animation, overriding the implicit animation.
[circleLayer addAnimation:animation forKey:animation.keyPath];

How to move and rotate object in iphone

I am developing a small game in iphone... Game concept is place an object in top of the bar...Rotating a bar using accelerometer. When bar rotating , i need to move an object with respect to bar. How to implement this concept...Any examples or references?
Rotating both img:
barImg,objImg //UIImageView
barImg.transform = CGAffineTransformMakeRotation(Ypos);
objImg.transform=CGAffineTransformMakeRotation(Ypos);
So for rotating 360 Degree with animation:
CABasicAnimation *rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:-M_PI * 2.0]; // full rotation*/ * rotations * duration ];
rotationAnimation.duration = 1;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = MAXFLOAT;
[rotatingTelIamgeview.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
you can play with toValue for changing the angle.
For moving an object:
CGPoint startPoint = CGPointMake(lvMessageInputBar.animationBubbleImageView.layer.frame.origin.x+lvMessageInputBar.animationBubbleImageView.layer.frame.size.width/2
, lvMessageInputBar.animationBubbleImageView.layer.frame.origin.y +lvMessageInputBar.animationBubbleImageView.layer.frame.size.height/2 );
CGPoint endPoint = CGPointMake(endPoint.origin.x+Endpoint.size.width/2, bubleRect.origin.y+bubleRect.size.height/2);
CGPoint middlePoint = // any point between start and end corrdinates
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
CGPathAddQuadCurveToPoint(path, NULL,middlePoint.x, middlePoint.y,endPoint.x,endPoint.y);
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.delegate = self;
pathAnimation.removedOnCompletion = NO;
pathAnimation.path = path;
[pathAnimation setCalculationMode:kCAAnimationCubic];
[pathAnimation setFillMode:kCAFillModeForwards];
pathAnimation.duration = 0.3;
[lvMessageInputBar.animationBubbleImageView.layer addAnimation:pathAnimation forKey:nil];
The above example moves the layer of the object over a path.but CGPathAddQuadCurveToPoint makes the path not diagonal rather circular path (curve).
you can use CGPathAddPath if you do not want this effect.
If you are new to iPhone I would start with layer tutorial to get the idea behind CALayer and then take a look CALayer animations
CALayers introduction:
https://www.raywenderlich.com/3096-calayers-tutorial-for-ios-introduction-to-calayers
CALayer Animation documentation of from Apple:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html
You can also watch Session 424 (Core Animation in Practice, Part 1) and 425 (Core Animation in Practice, Part 2) of WWDC 2010:
https://developer.apple.com/videos/archive/

Manipulating UIImageView During Animation with CAKeyframeAnimation

I need to move object (UIImageView) from point A to point B, then rotate image at point B by 180 degrees to face the opposite direction and move object from B to A (backwards).
I have the code below which moves from A to B. I also know how to rotate UIImageView. But how to know when object has reached point B and how to apply rotation action considering there are many objects on the screen?
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = speed;
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
CGMutablePathRef pointPath = CGPathCreateMutable();
CGPathMoveToPoint(pointPath, NULL, rect.origin.x, rect.origin.y);
CGPathAddLineToPoint(pointPath, NULL, x, y);
pathAnimation.path = pointPath;
CGPathRelease(pointPath);
[imageView.layer addAnimation:pathAnimation forKey:[NSString stringWithFormat:#"pathAnimation%#",objId]];
[imageView release];
Set a delegate on the CAAnimation object, and in the delegate implement the animationDidStop:finished: method.
OTOH, the animation you described sounds like it could be done easily enough with UIView's animation support. See Animating Views with Blocks if you're targeting 4.0 and up, or Animating Views if you're still targeting earlier versions.
You can use the CAAnimation delegate method
-(void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

UIImageView XY Coordinates with Layer Movement

I move my UIImageView with layer around the screen. When at some point I'm trying to retrieve x and y coordinates of a moved imageView using imageView.frame.origin.x I receive original coordinates not the new ones after the move. How to get X and Y correctly?
Here is my code:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:rect];
imageView.animationImages = [NSArray arrayWithArray:imgNameArr];
imageView.animationDuration = 2;
imageView.animationRepeatCount = 0;
[imageView startAnimating];
[self.view addSubview:imageView];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = speed;
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
CGMutablePathRef pointPath = CGPathCreateMutable();
CGPathMoveToPoint(pointPath, NULL, rect.origin.x, rect.origin.y);
CGPathAddLineToPoint(pointPath, NULL, x, y);
pathAnimation.path = pointPath;
CGPathRelease(pointPath);
[imageView.layer addAnimation:pathAnimation forKey:[NSString stringWithFormat:#"pathAnimation%#",objId]];
[imageView release];
Per the UIView documentation for the frame property:
Warning: If the transform property is not the identity transform, the
value of this property is undefined and therefore should be ignored.
The frame property also becomes undefined if you adjust that view's layer's transform or affineTransform properties (which are actually what the UIView alters when you set its transform). In Cocoa Touch transforms are applied at the time of compositing by the compositor. At present what you seem to get when a transform is applied is the original frame as though there were no transform, but as the docs say it's undefined so don't rely on that.
If you're just moving the view around with no other transformation, I recommend you use the view's center property rather than applying a transform. That will update your frame correctly. Based on empirical evidence, UIKit also seems smart enough that just adjusting the centre doesn't have any performance downside compared to applying a transform.

UIView animation along a round path?

I need to make my little guy (in a UIIamgeView) jump forward and it has to look natural. I want to know is there a way to do it with CoreAnimation (beginAnimation/commitAnimation)?
I could do it by setting a point in between in the air but the movement looks not natural :P
Reading Brad Larson's post, I ended up with a nice function to make my image follow a circle.
You need to import QuartzCore framework: #import
Here is the code:
// Set up path movement
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.repeatCount = INFINITY;
//pathAnimation.rotationMode = #"auto";
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
pathAnimation.duration = 5.0;
// Create a circle path
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGRect circleContainer = CGRectMake(0, 0, 400, 400); // create a circle from this square, it could be the frame of an UIView
CGPathAddEllipseInRect(curvedPath, NULL, circleContainer);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
[self.imageView.layer addAnimation:pathAnimation forKey:#"myCircleAnimation"];
Create a CAKeyframeAnimation and assign a CGPath to its path property.
To follow up on Ole's answer, my answer to this question provides code to perform such a curved animation using a CAKeyframeAnimation.