smooth pendular animation with Core Animation Framework - iphone

im trying to do an animation with an uiimageview.
in this view is an image with an arrow, that i want to rotate about 45 degrees back and forward very smoothly like an pendular or an old clock.
something like this, just smooth and with my image: http://bit.ly/cArvNw (found this with google ;) )
my current setup looks like this:
UIImageView* rotatingImage = [[UIImageView alloc] initWithFrame:CGRectMake(10.0, 10.0, 200.0, 200.0)];
[rotatingImage setImage:[UIImage imageNamed:#"wind.png"]];
CALayer *layer = rotatingImage.layer;
CAKeyframeAnimation *animation;
animation = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.duration = 0.5f;
animation.cumulative = YES;
animation.repeatCount = 100;
animation.values = [NSArray arrayWithObjects: // i.e., Rotation values for the 3 keyframes, in RADIANS
[NSNumber numberWithFloat:[self degreesToRadians:45.0]],
[NSNumber numberWithFloat:[self degreesToRadians:-45.0]], nil];
animation.keyTimes = [NSArray arrayWithObjects: // Relative timing values for the 3 keyframes
[NSNumber numberWithFloat:0],
[NSNumber numberWithFloat:.5], nil];
animation.timingFunctions = [NSArray arrayWithObjects:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], // from keyframe 1 to keyframe 2
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil]; // from keyframe 2 to keyframe 3
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[layer addAnimation:animation forKey:nil];
[self addSubview:rotatingImage];
this is really a pain, add 45 degrees, then 45 degrees backward with "-45" doesnt work.
im very new to core animation and dont know how to setup my code, to get my wanted animation.
can anybody help please?

Have you looked at Apple's Example iPhone Application, "Metronome"?
It does almost exactly what you're trying to do, using Core Animation.

Note: This method does not use Core Animation, but it's very simple and probably uses less resources.
First, make the UIImageView twice as tall, thereby making the center of rotation equal to the center of the image.
Then, define these in the #interface of the header file (of, say, your UIViewController):
BOOL goingCW; // going clockwise = YES, going counterclockwise = NO
CGFloat angle; // angle by which to change the image's rotation value
Then put this in an init method that runs once:
goingCW = YES; // change this to NO to make it start rotating CCW instead
angle = 0;
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(update) userInfo:nil repeats:YES];
Then define update, given that arrow is the UIImageView instance:
- (void)update {
if (goingCW) {
if (angle > M_PI / 4) goingCW = NO; // M_PI / 4 is equal to 45 degrees
angle += M_PI / 60; // increase 60 to slow down the rotation, etc.
} else {
if (angle < -M_PI / 4) goingCW = YES; // -M_PI / 4 is equal to -45 degrees
angle -= M_PI / 60; // increase 60 to slow down the rotation, etc.
}
// rotate the UIImageView appropriately
arrow.transform = CGAffineTransformMakeRotation(angle);
}
This also assumes that you are starting in the facing-down position.

Related

how to increase and decrease the image alpha value with animation in ios sdk?

In this code i am using animation.But at a time i need to change the image alpha value also.
-(void)animation
{
CGPoint point = CGPointMake(imgView.frame.origin.x, imgView.frame.origin.y);
imgView.layer.position = point;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"position.x"];
anim.fromValue = [NSValue valueWithCGPoint:point];
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(point.x + 50, point.y)];
anim.duration = 10.0f;
anim.repeatCount =1;
anim.removedOnCompletion = YES;
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[imgView.layer addAnimation:anim forKey:#"position.x"];
imgView.layer.position = point;
}
You can use the opacity key of CABasicAnimation for doing this:
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:#"opacity"];
alphaAnimation.fromValue = [NSNumber numberWithFloat:1.0];
alphaAnimation.toValue = [NSNumber numberWithFloat:0.0];
[imgView.layer addAnimation:alphaAnimation forKey:#"opacity"];
Edit:
For animating through specified values you can use CAKeyframeAnimation:
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"opacity"];
animation.duration = 10.0f;
animation.repeatCount = 1;
animation.values = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:1.0,
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:1.0],nil];
animation.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:5.0],
[NSNumber numberWithFloat:10.0], nil];
[imgView.layer addAnimation:animation forKey:#"opacity"];
In order to decrease the alpha as the same time/rate the x position of your view is moving, just put the position setting code together with the alpha setting code in the same block of animation, like below:
CGPoint finalPoint = CGPointMake(500, imgView.center.y); //change for any final point you want
CGFloat finalAlpha = 0.0; //change the final alpha as you want
UIView animateWithDuration:1.0 animations:^{ //change the duration as you want
imgView.alpha = finalAlpha;
imgView.center = finalPoint;
}];
This "fades to invisible" self.view in 500ms.
Anything you do prior to invoking it will be set "immediately", everything you set within the `animation' block (like setting new frame coordinates) will be interpolated over the specified duration.
[UIView animateWithDuration:0.50
delay:0.0
options:( UIViewAnimationOptionAllowUserInteraction
| UIViewAnimationOptionBeginFromCurrentState
| UIViewAnimationOptionCurveEaseInOut)
animations:^ {
self.view.alpha = 0.0f ;
}
completion: ^(BOOL){
[self.view removeFromSuperview] ;
self.view = nil ;
}
] ;
You may use a CABasicAnimation object (a different one because you will animate a different KeyPath, namely alpha, for this) and use NSNumbers for fromValue and toValue.
Another (and easiest) way is to use the UIView helper methods dedicated to animation ( animateWithDuration:… and all), especially if you have to animate multiple properties at the same time (you may animate both the frame and the alpha with the same animation block if it fits your needs and simplify your code).
You can also mix CABasicAnimation for the frame and [UIView animateWithDuration:…] for the alpha, whatever combination you need depending on if your animations are complex and need to be customized (custom timing function, non-linear animation, …) or not.
//your code of changing x position will be here
now implement my code which is written below.
UIView animateWithDuration:1.0 animations:^{
imgView.alpha = 0.5;//must be in between 0 to 1
}];
now when your imageview move to next position as you are saying, write below code
//your code for imageview for next position..
now implement below code...
UIView animateWithDuration:0.5 animations:^{
imgView.alpha = 1.0;//must be in between 0 to 1
}];
let me know it is working or not!!!! Hope it helps...
Happy Coding!!!

Rotating animation

I'm rotating an arrow by 45 degrees. When an animation ends, the arrow returns to its original state (0 degrees). I need that the arrow doesn't return to original state and it will be rotate by 45 degrees at the end of animation.
CABasicAnimation *fullRotationShort = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotationShort.fromValue = [NSNumber numberWithFloat:0];
fullRotationShort.toValue = [NSNumber numberWithFloat:M_PI/28*4.7];
fullRotationShort.duration = 1.0f;
fullRotationShort.repeatCount = 1;
[imgViewArrowShort.layer addAnimation:fullRotationShort forKey:nil];
Assuming your arrow is a UIImageView named arrow.
You really don't need such complicated CAAnimations for this.
[UIView animateWithDuration:1.0 animations:^{
arrow.transform = CGAffineTransformMakeRotation(0.25 * M_PI);
}];
Set the property:
fullRotationShort.fillMode = kCAFillModeForwards;
fullRotationShort.cumulative = YES;
fullRotationShort.removedOnCompletion=NO;

How to rotate image 360 degrees endlessly using iPhone SDK?

I want to rotate image 360 degrees endlessly using iPhone SDK?
How can this be done?
Thanks!
-(void)startAnimationWithRevolutions:(float)revPerSecond forTime:(float)time
{
spinWheel.userInteractionEnabled = FALSE;
float totalRevolutions = revPerSecond * time;
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:time] forKey:kCATransactionAnimationDuration];
CABasicAnimation* spinAnimation = [CABasicAnimation
animationWithKeyPath:#"transform.rotation"];
CGAffineTransform transform = spinWheel.transform;
float fromAngle = atan2(transform.b, transform.a);
float toAngle = fromAngle + (totalRevolutions*4*M_PI);
spinAnimation.fromValue = [NSNumber numberWithFloat:fromAngle];
spinAnimation.toValue = [NSNumber numberWithFloat:toAngle];
spinAnimation.repeatCount = 0;
spinAnimation.removedOnCompletion = NO;
spinAnimation.delegate = self;
spinAnimation.timingFunction = [CAMediaTimingFunction functionWithName:
kCAMediaTimingFunctionEaseOut];
[spinWheel.layer addAnimation:spinAnimation forKey:#"spinAnimation"];
[CATransaction commit];
}
Try using this, it works.
Assuming you are displaying the image in a UIImageView, you can rotate the view's local coordinate system (see here) and use NSTimer to increase the rotation periodically (see here).
(I would use OpenGL for this, but that's just a personal preference and is probably overkill for your situation.)

How can I enforce an specific direction (i.e. clockwise) of rotation in Core Animation?

I am rotating a view with this:
CGAffineTransform rotatedTransform = CGAffineTransformRotate(CGAffineTransformIdentity, rotationValue);
I have an object which I want to spin around for about 320 degrees. Now Core Animation is clever and just rotates it as much as needed, doing that by rotating it with -40 degrees. So the object rotates the other way around with a shorter amount of movement.
I want to constrain it to rotate clockwise. Would I have to do that by changing animations in little steps, or is there an more elegant way?
The following snippet rotates a view called someView by using key-framed animation. The animation consists of 3 frames spread over 1 second, with the view rotated to 0º, 180º and 360º in the first, second and last frames respectively. Code follows:
CALayer* layer = someView.layer;
CAKeyframeAnimation* animation;
animation = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.duration = 1.0;
animation.cumulative = YES;
animation.repeatCount = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.values = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0 * M_PI],
[NSNumber numberWithFloat:0.5 * M_PI],
[NSNumber numberWithFloat:1.0 * M_PI], nil];
animation.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:1.0], nil];
animation.timingFunctions = [NSArray arrayWithObjects:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], nil];
[layer addAnimation:animation forKey:#"transform.rotation.z"];
If you're after counterclockwise animation, you should use negative values. For a slightly more basic animation, you can use CABasicAnimation:
CALayer* layer = someView.layer;
CABasicAnimation* animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:0.0 * M_PI];
animation.toValue = [NSNumber numberWithFloat:1.0 * M_PI];
animation.duration = 1.0;
animation.cumulative = YES;
animation.repeatCount = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[layer addAnimation:rotationAnimation forKey:#"transform.rotation.z"];
I believe you have to give it another "key frame" if you will to give Core Animation the hint that it needs to go that direction.
Make sure and turn off easing, (at least for the end/beginning of the middle step) otherwise the animation will not look smooth.

Moving Image 360 Degree

How can we Move an Image 360 Degree from the starting point to the ending point?
Moving Image 360 Degree?
You can rotate a view, by some number of radians, regardless of whether it is less than a full rotation or many multiples of a full rotation, without having to split the rotation into pieces. As an example, the following code will spin a view, once per second, for a specified number of seconds. You can easily modify it to spin a view by a certain number of rotations, or by some number of radians.
- (void) runSpinAnimationWithDuration:(CGFloat) duration;
{
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[myView.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
A 360 degree rotation in any axis leaves the view unchanged. So don't touch the image, and you're good to go!
You could use an animation function (CAValueFunction) for this too:
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
rotationAnimation.duration = duration;
rotationAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotationAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2.0];
rotationAnimation.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[myView.layer addAnimation:rotationAnimation forKey:nil];