I've this code for endless rotating an UIImageView
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationOptionCurveLinear|UIViewAnimationOptionRepeat
animations: ^{
self.spinner.transform = CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI);
}
completion: ^(BOOL finished) {
}];
But the first I call this method the image, it rotate clockwise instead anti clockwise. If I re-call this method while image is rotating, it change direction and start rotate anti clockwise.
Ideas?
Use a CABasicAnimation instead since it is far more powerful. You have to call the below snippet only once and the animation will run indefinitely:
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotate.toValue = #(M_PI * 2); // use #(-M_PI * 2) for counter clockwise
rotate.duration = 0.3;
rotate.cumulative = true;
rotate.repeatCount = HUGE_VALF;
[self.spinner.layer addAnimation:rotate forKey:#"rotateAnim"];
Swift:
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.toValue = M_PI * 2
rotate.duration = 0.3
rotate.cumulative = true
rotate.repeatCount = HUGE
self.spinner.layer.addAnimation(rotate, forKey: "rotateAnim")
From the documentation:
In iOS, a positive value specifies counterclockwise rotation and a
negative value specifies clockwise rotation.
CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI)
Update: M_PI is constant not effected by the negative value. Somehow -M_PI is still taken as positive at the end!!!
If you give -180 it will rotate in clockwise, and if you give 180 it will rotate anti-clockwise
Related
I am able to rotate an image a certain number of degrees continuously, but I want to rotate the image a tiny amount, pause, a little more, pause, etc.
The follow code does this continuously:
// rotate
CGFloat finalValue = 360 / 14.f;
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
[rotationAnimation setFromValue:[self degreesToNumber:0]];
[rotationAnimation setToValue:[self degreesToNumber:finalValue]];
[rotationAnimation setDuration:5.0];
[rotationAnimation setRemovedOnCompletion:NO];
[rotationAnimation setFillMode:kCAFillModeForwards];
[self.secondHandImageView.layer addAnimation:rotationAnimation forKey:#"rotate"];
Is there a way to wrap this in a for-loop with the number of angle changes I need and set the duration and delay of the specific animations? Nothing I have tried works. Below is what I am currently trying:
// rotate in ticks, so
NSTimeInterval delay = 0;
CGFloat currentAngle = 0;
CGFloat finalAngle = 360 / 14.f;
// angle difference
CGFloat numberOfTicks = 25.f;
CGFloat angleDelta = finalAngle / numberOfTicks;
for (NSUInteger tick = 0; tick < numberOfTicks; tick++) {
[UIView animateWithDuration:0.1 delay:delay options:UIViewAnimationOptionCurveLinear animations:^{
self.secondHandImageView.layer.transform = CATransform3DMakeRotation(0, 0, angleDelta, 1.0);
} completion:nil];
// update delay
delay += .2; // 200 milliseconds, 5 tickets every second
currentAngle += angleDelta;
}
You code is OK - except that you can't animate layers inside UIView animation blocks. Instead you can animate the view. Replace the (3D)layer transform with a (2D)view transform:
self.secondHandImageView.transform =
CGAffineTransformRotate(self.tickView.transform,angleDelta);
I want to perform an infinite 360 degrees rotation animation, so I coded:
- (void)rotate
{
__weak typeof(self) weakSelf = self;
[CATransaction begin];
[CATransaction setDisableActions:NO];
[CATransaction setCompletionBlock:^{
[weakSelf rotate];
}];
[CATransaction setAnimationDuration:1.0];
[CATransaction setAnimationTimingFunction:
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
self.squareLayer.transform = CATransform3DRotate(self.squareLayer.transform, M_PI, 0, 0, 1);
[CATransaction commit];
}
M_PI means 180 degrees, so I believe the layer can be rotated from 0 to M_PI * 1, M_PI * 2 ...
But it turns out to be an rotation from 0 to M_PI, then M_PI to 0.
I can make it through a CABasicAnimation:
CABasicAnimation *animatin = [CABasicAnimation animationWithKeyPath:#"transform"];
animatin.duration = 1.0;
animatin.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0, 0, 0, 1)];
animatin.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)];
animatin.repeatCount = HUGE_VALF;
animatin.fillMode = kCAFillModeForwards;
[self.squareLayer addAnimation:animatin forKey:#"a"];
Codes above rotate the layer 360 degrees perfectly.
But I am really confused about the first implementation, why it rotates so strange?
It's an edge case. With implicit animation, you are not able to say "rotate clockwise this amount". You are merely saying "set the transform to this value, and animate that effect." Well, how should that change be animated? The runtime has to make up an answer, and it isn't obvious how to do that. A transform of rotation by M_PI is the same "distance" in both directions, so the answer it makes up is arbitrary. You can see the problem even more clearly if you supply a value of M_PI+0.1 vs. a value of M_PI-0.1; you actually get reverse results: one keeps turning clockwise, the other keeps turning counterclockwise.
With CABasicAnimation, on the other hand, you have a from-value (implicit or explicit) and a to-value, so you are able to express the notion "increase" (i.e. a positive difference means turn clockwise). It's even clearer if you animate by setting just the byValue.
I have an issue.
i have this code:
if(CGRectContainsPoint(compassTarcsa.frame, curLoc))
{
compassTarcsaTouch = YES;
float fromAngle = atan2( compassFirstLoc.y-compassTarcsa.center.y,compassFirstLoc.x-compassTarcsa.center.x );
float toAngle = atan2( curLoc.y-compassTarcsa.center.y,curLoc.x-compassTarcsa.center.x );
newAngle = (angle + (toAngle - fromAngle));
iranyFok = (newAngle / (M_PI / 180.0f)) ;
if (iranyFok < 0.0f) {
iranyFok += 360.0f;
}
iranyFok = 360-(fmodf(( 360 + iranyFok ), 360));
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(- iranyFok));
compassTarcsa.transform = cgaRotate;
repcsi.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(iranyFok));
This rotates a compass from 0 to to 360 degrees, but the rotation speed is fast for me...
Can somebody help me understand how to slow this rotate?
Thx,
Alex
Try this:
[UIView animateWithDuration:2.0 delay:0 options: UIViewAnimationOptionCurveEaseInOut
animations:^(void){
compassTarcsa.transform = cgaRotate;
} completion:NULL
];
This will wrap your transform rotation in an animation that allows you to control the rotation duration.
You should consider using rotation animation and set its duration as per your required speed if you want slow rotation of an object.
Following links may be helpful to you:
UIView Infinite 360 degree rotation animation?
http://iosdevelopertips.com/user-interface/rotate-an-image-with-animation.html
In my iphone app I have a UIButton that I rotate 180 degrees into view when another UIButton is pressed, then when clicked again the button rotates a further 180 degrees back to where it started.
This all works fine the very first time the complete 360 degree process occurs, but if I try to start from the start again it snaps 180 degrees then tries to rotate it from that point. Can anyone point me in the right direction? Here's my code so far...
showAnimation= [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation"];
showAnimation.duration = self.showAnimationDuration;
showAnimation.repeatCount = 1;
showAnimation.fillMode = kCAFillModeForwards;
showAnimation.removedOnCompletion = NO;
showAnimation.cumulative = YES;
showAnimation.delegate = self;
float currentAngle =[[[rotateMe.layer presentationLayer] valueForKeyPath:#"transform.rotation.z"] floatValue];
//Rotate 180 degrees from current rotation
showAnimation.values = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:currentAngle],
[NSNumber numberWithFloat:currentAngle + (0.5 * M_PI)],
[NSNumber numberWithFloat:currentAngle + M_PI], nil];
[rotateMe.layer addAnimation:showAnimation forKey:#"show"];
On completion of the animation I then update the rotateMe.transform rotation to the layer's rotation so that it becomes usable.
- (void)animationDidStop:(CAKeyframeAnimation *)anim finished:(BOOL)flag
{
float currentAngle =[[[self.layer presentationLayer] valueForKeyPath:#"transform.rotation.z"] floatValue];
NSLog(#"End: %f", currentAngle);
rotateMe.transform = CGAffineTransformMakeRotation(0);
}
I have achieved the fully working effect with
[UIView animateWithDuration:1.0f]
animations:^{
CGAffineTransform transform = CGAffineTransformRotate(rotateMe.transform, DEGREES_TO_RADIANS(179.999f));
rotateMe.transform = transform;
}
];
But I'd like to make the animation more complex, hence the CAKeyframeAnimation.
You could configure the animation to be additive and animate from 0 to 180 degrees if you need all the key frames. If you don't need the different key frames the you can simply do it with a basic animation and the byValue property. The next time the animation is added it rotate 180 more degrees than whatever rotation is on the view.
If you are setting the actual value in the delegate callback then there is no need for fill mode and not removing the animation on completion.
CABasicAnimation *showAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
showAnimation.byValue = M_PI;
showAnimation.duration = self.showAnimationDuration;
showAnimation.delegate = self;
[rotateMe.layer addAnimation:showAnimation forKey:#"show"];
or using a key frame animation (as explained above: make it additive and animate from 0 to 180 degrees).
CAKeyframeAnimation *showAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation.z"];
showAnimation.additive = YES; // Make the values relative to the current value
showAnimation.values = #[0, /*all your intermediate values here... ,*/ M_PI];
showAnimation.duration = self.showAnimationDuration;
showAnimation.delegate = self;
[rotateMe.layer addAnimation:showAnimation forKey:#"show"];
Hello I have an image that I'd like to move up and down (Up 10 pixels and down 10 pixels) so that my image appears to be hovering. How can I do this with simple animation thanks so much!!!
You could use Core Animation to animate the position of the views layer. If you configure the animation to be additive you won't have to bother calculating the new absolute position, just the change (relative position).
CABasicAnimation *hover = [CABasicAnimation animationWithKeyPath:#"position"];
hover.additive = YES; // fromValue and toValue will be relative instead of absolute values
hover.fromValue = [NSValue valueWithCGPoint:CGPointZero];
hover.toValue = [NSValue valueWithCGPoint:CGPointMake(0.0, -10.0)]; // y increases downwards on iOS
hover.autoreverses = YES; // Animate back to normal afterwards
hover.duration = 0.2; // The duration for one part of the animation (0.2 up and 0.2 down)
hover.repeatCount = INFINITY; // The number of times the animation should repeat
[myView.layer addAnimation:hover forKey:#"myHoverAnimation"];
Since this is using Core Animation you will need to add QuartzCore.framework and #import <QuartzCore/QuartzCore.h> into your code.
For Swift 3, Swift 4 and Swift 5:
let hover = CABasicAnimation(keyPath: "position")
hover.isAdditive = true
hover.fromValue = NSValue(cgPoint: CGPoint.zero)
hover.toValue = NSValue(cgPoint: CGPoint(x: 0.0, y: 100.0))
hover.autoreverses = true
hover.duration = 2
hover.repeatCount = Float.infinity
myView.layer.add(hover, forKey: "myHoverAnimation")
Try this:
CGRect frm_up = imageView.frame;
frm_up.origin.y -= 10;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeats
animations:^{
imageView.frame = frm_up;
}
completion:NULL
];
For such a task, it will be better to place an image in a sublayer of UIView, and then animate that sublayer frame. This tutorial could give you some idea: http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial