CABasicAnimation of object around itself (360 degrees) - ios

Here's my Animation code:
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 4;
fullRotation.repeatCount= 1000;
[[stick layer] addAnimation:fullRotation forKey:#"60"];
fullRotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
I'm trying to rotate "stick" around itself , but it seems that it's rotating around another point , which is by default the origin. What can I do to make it accomplish a full 360 degrees rotation around itself? Thanks in advance.

If you want to change the anchor point of stick use:
stick.layer.anchorPoint = CGPointMake(1.0,1.0);
https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instp/CALayer/anchorPoint
The rotation code I use:
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotateAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotateAnim.fromValue = [NSNumber numberWithFloat:0];
rotateAnim.toValue = [NSNumber numberWithFloat:(360 * M_PI / 180.0f)];
rotateAnim.repeatCount = HUGE_VALF;
rotateAnim.duration = 2.5;
rotateAnim.removedOnCompletion = NO;
[view.layer addAnimation:rotateAnim forKey:#"rotationAnimation"];

Related

Glitches when queuing CAAnimations

I have a CAShapeLayer where I animate a circle. The animation is to first "undraw" the circle clockwise and then redraw the circle clockwise. Sort of a "rotating circle". Another way to put it: Move path stroke end point to start, then move the start point to the end.
The animation itself works, but it produces glitches now and then. It manifests in a short glimpse of the entire circle when it is supposed to be "undrawn".
Why does this occur and how can you fix it?
Thanks,
// Shape creation
layer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, self.width - 2 * OUTER_BORDER_WIDTH, self.width - 2* OUTER_BORDER_WIDTH)].CGPath;
// Animation queuing
-(void) applyNextAnimation
{
CABasicAnimation* animation;
if (self.animatingOpening)
{
animation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
self.animatingOpening = NO;
}
else
{
animation = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
self.animatingOpening = YES;
}
animation.duration = 1.0f;
animation.autoreverses = NO;
animation.delegate = self;
animation.removedOnCompletion = YES;
[self.outerCircleLayer addAnimation:animation forKey:#"stroke"];
}
// Animation stop callback
-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if (self.isAnimating)
{
[self applyNextAnimation];
}
}
It blinks becuase you are not setting the corresponding property on the layer. So when the animation completes, the layer's model is still in the pre-animated state and that is what you see momentarily between the two animations.
This will get you towards what you want...
if (self.animatingOpening)
{
self.outerCircleLayer.strokeStart = 0.0;
animation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
self.animatingOpening = NO;
}
else
{
self.outerCircleLayer.strokeStart = 1.0;
animation = [CABasicAnimation animationWithKeyPath:#"strokeStart"];
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
self.animatingOpening = YES;
}
animation.duration = 1.0f;
animation.autoreverses = NO;
that almost works, but you will notice a more subtle glitch as you transition from the undrawn state to start animating the drawing state. The beginning of the circle has a small reverse animation as it starts. This is an implicit animation triggered by setting strokeStart from 1.0 to 0.0: which you need to get rid of so that all of the animations effects are under your control. You can achieve that most simply by setting disableActions to YES on CATransaction:
[CATransaction setDisableActions:YES];
( add it just above if (self.animatingOpening))

Rotating UIImageView around anchorpoint issues

I am attempting to rotate a UIImageView around an anchor point to simulate a "radar sweep" style animation. My understanding of anchor points leads me to believe that (1, 1) should be the bottom right corner of the radar image. However, setting the ImageView's anchor point to this doesn't give me the behavior I anticipated. This can be viewed here.
As can be seen, the anchor point is a ways up the right side of the image, though it is correctly at the center. What I want is the image to rotate around the center point, like a radar sweep.
Here is the relevant code:
self.radarView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, barDimension, barDimension)];
self.radarView.contentMode = UIViewContentModeScaleAspectFill;
self.radarView.image = [UIImage imageNamed:#"radarSweep.png"];
self.radarView.layer.anchorPoint = CGPointMake(1, 1);
self.radarView.layer.position = CGPointMake(screenWidth / 2.0, screenHeight / 2.0);
[self.mapView addSubview:self.radarView];
CABasicAnimation *opacityInAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
[opacityInAnim setFromValue:[NSNumber numberWithFloat:0.0]];
[opacityInAnim setToValue:[NSNumber numberWithFloat:1.0]];
opacityInAnim.duration = 0.25;
opacityInAnim.fillMode = kCAFillModeForwards;
opacityInAnim.removedOnCompletion = NO;
opacityInAnim.beginTime = 0.0;
opacityInAnim.delegate = self;
[opacityInAnim setValue:#"radarSweep" forKey:#"animName"];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:0.0];
animation.toValue = [NSNumber numberWithFloat:2 * M_PI];
animation.duration = 1.0f;
animation.fillMode = kCAFillModeForwards;
animation.repeatCount = 2;
animation.removedOnCompletion = NO;
[animation setBeginTime:0.0];
animation.delegate = self;
[animation setValue:#"radarSweep" forKey:#"animName"];
animation.removedOnCompletion = YES;
CABasicAnimation *opacityOutAnimBar = [CABasicAnimation animationWithKeyPath:#"opacity"];
[opacityOutAnimBar setFromValue:[NSNumber numberWithFloat:1.0f]];
[opacityOutAnimBar setToValue:[NSNumber numberWithFloat:0.0f]];
opacityOutAnimBar.delegate = self;
opacityOutAnimBar.fillMode = kCAFillModeForwards;
opacityOutAnimBar.removedOnCompletion = NO;
[opacityOutAnimBar setDuration:0.25];
[opacityOutAnimBar setValue:#"radarSweep" forKey:#"animName"];
[opacityOutAnimBar setBeginTime:1.35];
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:2.0];
group.delegate = self;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[group setAnimations:#[opacityInAnim, animation, opacityOutAnimBar]];
[group setValue:#"radarSweep" forKey:#"animName"];
[self.radarView.layer addAnimation:group forKey:#"group"];
Any advice would be greatly appreciated. Thanks in advance.
Your radar image isn't square but the imageview is, so the image is bleeding over the bounds of the imageView. You can either do self.radarView.layer.clipsToBounds = YES or change the content mode to ScaleToFit. Or you can resize your image view to match the proportions of the radar image.

CALayer explicit animation

Guys I'm trying to perform a CABasicAnimation (just for the test purposes) following the Apple's guide
There's a piece of code:
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 5.0;
[theLayer addAnimation:fadeAnim forKey:#"opacity"];
// Change the actual data value in the layer to the final value.
theLayer.opacity = 0.0;
Which tells that I should actually change a property at the end. But it seems not working fine(it changes opacity immediately) - the duration is not 5 (I changed it to 5 for better visibility) so the animation is not CABasicAnimation but implicit.
It only works when I set theLayer.opacity = 0.0; BEFORE I add the animation to layer. Am I doing something wrong or it is a bug in docs?
P.S running the latest XCode, iOS 7.1 simulator.
Update the model layer before adding the animation.
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
fadeAnim.duration = 5.0;
// Change the actual data value in the layer to the final value.
theLayer.opacity = 0.0;
[theLayer addAnimation:fadeAnim forKey:#"opacity"];

how to animate the circle image using CAKeyFrameAnimation

I'm new in ios development.
I'm implementing an Animation project and I have a circle.png image.
How can I rotate the image using CAKeyFrameAnimation on that image?
Code:-
-(void)spinAnimation
{
CABasicAnimation *rotation;
rotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotation.fromValue = [NSNumber numberWithFloat:0];
rotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
rotation.duration = 1.1; // Speed
rotation.repeatCount = HUGE_VALF; // Repeat forever. Can be a finite number.
[yourimageview.layer addAnimation:rotation forKey:#"Spin"];
}
Hope it helps.

CABasicAnimation how to get current angle of rotation

I have some problem with CABasicAnimation. It`s similar to that post: CABasicAnimation rotate returns to original position
So, i have uiimageview that rotate in touchMove. In touchEnd invoke method that do "animation of inertia" :
-(void)animationRotation: (float)beginValue
{
CABasicAnimation *anim;
anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
anim.duration = 0.5;
anim.repeatCount = 1;
anim.fillMode = kCAFillModeForwards;
anim.fromValue = [NSNumber numberWithFloat:beginValue];
[anim setDelegate:self];
anim.toValue = [NSNumber numberWithFloat:(360*M_PI/180 + beginValue)];
[appleView.layer addAnimation:anim forKey:#"transform"];
CGAffineTransform rot = CGAffineTransformMakeRotation(360*M_PI/180 + beginValue);
appleView.transform = rot;
}
This animation works fine, but if I invoke touchBegan before animationRotation ended, angle of rotation is beginValue. I need cath current angle of rotation. As an experiment, i declare method
-(vod) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
NSLog(#"Animation finished!");
}
and it's seems working. but I don't know how get that value of angle or CGAffineTransform for my UIImageView in animationDidStop.
It's even possible to do? Thanks.
you should use presentationLayer method to get layer properties during animation in flight.
so your code should be like this,
#define RADIANS_TO_DEGREES(__ANGLE__) ((__ANGLE__) / (float)M_PI * 180.0f)
-(void)animationRotation: (float)beginValue
{
CABasicAnimation *anim;
anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
anim.duration = 0.5;
anim.repeatCount = 1;
anim.fillMode = kCAFillModeForwards;
anim.fromValue = [NSNumber numberWithFloat:beginValue];
[anim setDelegate:self];
//get current layer angle during animation in flight
CALayer *currentLayer = (CALayer *)[appleView.layer presentationLayer];
float currentAngle = [(NSNumber *)[currentLayer valueForKeyPath:#"transform.rotation.z"] floatValue];
currentAngle = roundf(RADIANS_TO_DEGREES(currentAngle));
NSLog(#"current angle: %f",currentAngle);
anim.toValue = [NSNumber numberWithFloat:(360*M_PI/180 + beginValue)];
[appleView.layer addAnimation:anim forKey:#"transform"];
CGAffineTransform rot = CGAffineTransformMakeRotation(360*M_PI/180 + beginValue);
appleView.transform = rot;
}

Resources