Rotate and translate UIImageView off and on screen - iphone

How can I rotate and translate a UIImageView off one side of the screen, then its coming back from the other side..
Lets say I have a Wheel that I want to rotate and translate from the middle then off the screen to the left, then its "coming back" from the right side and back the middle..
I used following code to rotate and translate it OFF the screen;
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: -M_PI * 2.0 /* full rotation*/ * 2 * 1 ];
rotationAnimation.duration = 1;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
rotationAnimation.delegate = self;
CABasicAnimation* translationAnimation;
translationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
translationAnimation.toValue = [NSNumber numberWithFloat:-700];
translationAnimation.duration = 1;
translationAnimation.cumulative = YES;
translationAnimation.repeatCount = 1.0;
translationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
translationAnimation.removedOnCompletion = NO;
translationAnimation.fillMode = kCAFillModeForwards;
Dunno if this is the right way to go, so please help!

try This, it will Work for you
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: -M_PI * 2.0 /* full rotation*/ * 2 * 1 ];
rotationAnimation.duration = 1;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
rotationAnimation.delegate = self;
CABasicAnimation* translationAnimation;
translationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
translationAnimation.toValue = [NSNumber numberWithFloat:-700];
translationAnimation.duration = 1;
translationAnimation.cumulative = YES;
translationAnimation.repeatCount = 1.0;
translationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
translationAnimation.removedOnCompletion = NO;
translationAnimation.fillMode = kCAFillModeForwards;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:rotationAnimation,translationAnimation, nil];
group.delegate = self;
group.removedOnCompletion = NO;
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[[self.imageView.layer addAnimation:group forKey:#"randt"];

Swift 5.4.2 (based on Sanjeev Rao reply):
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationAnimation.toValue = NSNumber(floatLiteral: Double.pi * 2.0 /* full rotation*/ * 2 * 1)
rotationAnimation.duration = 1
rotationAnimation.isCumulative = true
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
rotationAnimation.delegate = self // can be skipped
let translationAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
translationAnimation.toValue = NSNumber(floatLiteral: -700)
translationAnimation.duration = 1
translationAnimation.isCumulative = true
translationAnimation.repeatCount = 1.0
translationAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
translationAnimation.isRemovedOnCompletion = false
translationAnimation.fillMode = .forwards
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [rotationAnimation, translationAnimation]
group.delegate = self // can be skipped
groupAnimation.isRemovedOnCompletion = false
groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
self.imageView.layer.add(groupAnimation, forKey: "randt")

Related

Jerky Animation for UiView PopOut

I have a UIView for which I am using the following code for pop-in animation
float duration=1.3f;
CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale"];
scale.duration = duration;
scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:.5f],
[NSNumber numberWithFloat:1.1f],
[NSNumber numberWithFloat:0.95f],
[NSNumber numberWithFloat:1.f],
nil];
CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeIn.duration = duration * .2f;
fadeIn.fromValue = [NSNumber numberWithFloat:0.f];
fadeIn.toValue = [NSNumber numberWithFloat:1.f];
fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
fadeIn.fillMode = kCAFillModeForwards;
CAAnimationGroup *animationgroup = [CAAnimationGroup animation];
animationgroup.delegate=self;
animationgroup.animations = [NSArray arrayWithObjects:scale, fadeIn, nil];
animationgroup.duration = duration;
animationgroup.fillMode = kCAFillModeForwards;
animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[animationgroup setValue:#"popIn" forKey:#"name"];
animationgroup.fillMode=kCAFillModeForwards;
[self.view.layer addAnimation:animationgroup forKey:#"popIn"];
That works fone. It pops In the view in perfect way. But the code of pop-out animation is gives a jerk at end of animation that looks quite wierd.
Here is my popout code
float duration=0.15f;
CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale"];
scale.duration = duration;
scale.removedOnCompletion = NO;
scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:1.f],
[NSNumber numberWithFloat:1.1f],
[NSNumber numberWithFloat:.15f],
nil];
CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeOut.duration = duration * .4f;
fadeOut.fromValue = [NSNumber numberWithFloat:1.f];
fadeOut.toValue = [NSNumber numberWithFloat:0.f];
fadeOut.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
fadeOut.beginTime = duration * .6f;
fadeOut.fillMode = kCAFillModeBoth;
CAAnimationGroup *animationgroup = [CAAnimationGroup animation];
animationgroup.animations = [NSArray arrayWithObjects:scale, fadeOut, nil];
animationgroup.duration = duration;
animationgroup.fillMode = kCAFillModeForwards;
animationgroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
[animationgroup setValue:#"popOut" forKey:#"name"];
animationgroup.fillMode=kCAFillModeForwards;
[self.view.layer addAnimation:animationgroup forKey:#"popOut"];
The scale sequence 1.0, 1.1, 0.15 should result in a jerk.
If you are not satisfied with the visual results, try fiddling with the values above and the timing function (you are using "easeIn" instead of "easeInOut").
During Animation only the presentation layer gets changes while the modal layer of the view stays to its original state.
In your case you are not preserving the state of presentation layer when animation is finished and Modal layer appears which is in it original form. which seems like the Jerk effect.
Use the following line after "animationgroup.fillMode=kCAFillModeForwards;" to preserve the presentation layer state and the jerk will go away.
animationgroup.removedOnCompletion=NO;

UIScrollview gets slow after CABasicAnimations

as the title suggest, I'm having problems with my UIScrollview, which movements get jerky after I play a CABasicAnimation. The animation flips the UI elements on the screen (up to 10) around while fading them out. To do this, I use the code below:
-(void)flipLayers:(UIView *)view {
CGFloat subviewX = ((1/view.frame.size.width)*(view.frame.origin.x+200));
CGFloat subviewY = 0.5;
[self setAnchorPoint:CGPointMake(-subviewX, subviewY) forView:view];
CALayer *layer = view.layer;
layer.shouldRasterize = YES;
CATransform3D aTransform = CATransform3DIdentity;
CGFloat zDistance = 2000;
aTransform.m34 = 1.0 / -zDistance;
scrollView.layer.sublayerTransform = aTransform;
CATransform3D bTransform = CATransform3DIdentity;
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
rotateAnim.fromValue= [NSValue valueWithCATransform3D:bTransform];
bTransform = CATransform3DRotate(aTransform, -M_PI_2, 0, 1, 0);;
rotateAnim.duration=0.2;
rotateAnim.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseIn];
rotateAnim.toValue=[NSValue valueWithCATransform3D:bTransform];
layer.transform = bTransform;
rotateAnim.removedOnCompletion = YES;
[layer addAnimation:rotateAnim forKey:nil];
CABasicAnimation *fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.duration = 0.12;
fadeAnim.removedOnCompletion = YES;
fadeAnim.beginTime = CACurrentMediaTime() + 0.08;
fadeAnim.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnim.toValue = [NSNumber numberWithFloat:0.0];
[layer addAnimation:fadeAnim forKey:nil];
}
To restore the UI elements original position in a similar manner, I use this code
-(void)flipLayersBackwards:(UIView *)view {
CALayer *layer = view.layer;
CATransform3D aTransform = CATransform3DIdentity;
CGFloat zDistance = 2000;
aTransform.m34 = 1.0 / -zDistance;
scrollView.layer.sublayerTransform = aTransform;
CATransform3D bTransform = CATransform3DIdentity;
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
rotateAnim.fromValue= [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0, 1, 0)];
bTransform = CATransform3DRotate(aTransform, 0, 0, 1, 0);;
rotateAnim.duration=0.2;
rotateAnim.removedOnCompletion = YES;
rotateAnim.toValue=[NSValue valueWithCATransform3D:bTransform];
rotateAnim.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
layer.transform = bTransform;
[layer addAnimation:rotateAnim forKey:#"rotateAnim"];
CABasicAnimation *fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.duration = 0.064;
fadeAnim.removedOnCompletion = YES;
fadeAnim.beginTime = CACurrentMediaTime() + 0.02;
fadeAnim.fromValue = [NSNumber numberWithFloat:0.0];
fadeAnim.toValue = [NSNumber numberWithFloat:1.0];
[layer addAnimation:fadeAnim forKey:nil];
layer.shouldRasterize = NO;
}
The more times the animation is used, the jerkier the scrollview's movement get. Does anyone have an idea what could be causing this? Any help on how to fix this would be greatly appreciated. Thanks in advance :)
EDIT: I have found that the perspective transform is the cause of the choppiness, but I have no idea what to do about it

iPhone UIImageView and CABasicAnimation

I am doing a simple card rotation which works fine, but when I add a custom image background, after the card roation, the image is half chopped off. Any ideas?
float scaleValue = M_PI/2;
CABasicAnimation *yRotation;
yRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
yRotation.fromValue = [NSNumber numberWithFloat:0.0];
yRotation.toValue = [NSNumber numberWithFloat:scaleValue];
yRotation.duration = .5;
CABasicAnimation *yRotation2;
yRotation2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
yRotation2.fromValue = [NSNumber numberWithFloat:scaleValue];
yRotation2.toValue = [NSNumber numberWithFloat:0.0];
yRotation2.duration = .5;
yRotation2.cumulative = YES;
yRotation2.beginTime = .5;
CAAnimationGroup *groupAnim = [CAAnimationGroup animation];
groupAnim.removedOnCompletion = NO;
groupAnim.duration = 1;
groupAnim.fillMode = kCAFillModeForwards;
groupAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
groupAnim.animations = [NSArray arrayWithObjects:yRotation, yRotation2, nil];
[[image objectAtIndex:num] addAnimation:groupAnim forKey:#"animateCard"];
[self.view bringSubviewToFront:[image objectAtIndex:num]];
This code is help to you .......
once try it will be perfectly working...without choppedoff
- (void)loadView {
[super loadView];
self.view.backgroundColor = [UIColor blackColor];
// Orbit #1
CALayer *orbit1 = [CALayer layer];
orbit1.bounds = CGRectMake(0, 0, 200, 200);
orbit1.position = self.view.center;
orbit1.cornerRadius = 100;
orbit1.borderColor = [UIColor redColor].CGColor;
orbit1.borderWidth = 1.5;
CALayer *planet1 = [CALayer layer];
planet1.bounds = CGRectMake(0, 0, 20, 20);
planet1.position = CGPointMake(100, 0);
planet1.cornerRadius = 10;
planet1.backgroundColor = [UIColor redColor].CGColor;
[orbit1 addSublayer:planet1];
CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim1.fromValue = [NSNumber numberWithFloat:0];
anim1.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
anim1.repeatCount = HUGE_VALF;
anim1.duration = 8.0;
[orbit1 addAnimation:anim1 forKey:#"transform"];
[self.view.layer addSublayer:orbit1];
// Orbit #2
CALayer *orbit2 = [CALayer layer];
orbit2.bounds = CGRectMake(0, 0, 120, 120);
orbit2.position = planet1.position;
orbit2.cornerRadius = 60;
orbit2.borderColor = [UIColor blueColor].CGColor;
orbit2.borderWidth = 1.5;
CALayer *planet2 = [CALayer layer];
planet2.bounds = CGRectMake(0, 0, 16, 16);
planet2.position = CGPointMake(60, 0);
planet2.cornerRadius = 8;
planet2.backgroundColor = [UIColor blueColor].CGColor;
[orbit2 addSublayer:planet2];
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim2.fromValue = [NSNumber numberWithFloat:0];
anim2.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
anim2.repeatCount = HUGE_VALF;
anim2.duration = 4.0;
[orbit2 addAnimation:anim2 forKey:#"transform"];
[orbit1 addSublayer:orbit2];
// Orbit #3
CALayer *orbit3 = [CALayer layer];
orbit3.bounds = CGRectMake(0, 0, 72, 72);
orbit3.position = planet2.position;
orbit3.cornerRadius = 36;
orbit3.borderColor = [UIColor grayColor].CGColor;
orbit3.borderWidth = 1.5;
CALayer *planet3 = [CALayer layer];
planet3.bounds = CGRectMake(0, 0, 12, 12);
planet3.position = CGPointMake(36, 0);
planet3.cornerRadius = 6;
planet3.backgroundColor = [UIColor grayColor].CGColor;
[orbit3 addSublayer:planet3];
CABasicAnimation *anim3 = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim3.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim3.fromValue = [NSNumber numberWithFloat:0];
anim3.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
anim3.repeatCount = HUGE_VALF;
anim3.duration = 2.0;
[orbit3 addAnimation:anim3 forKey:#"transform"];
[orbit2 addSublayer:orbit3];

Resizing layers and its sublayers - CoreAnimation

I have a CALayer A with one sublayer B
I want A to be resized (to be shrank) so I add the animations to my layer A
but when I commit the animation sublayer B is not shrank. Its size remains(but its position changes as its superlayer bounds changes)
How can I make my B layer to be resized along with A animation?
This is what I wrote:
CABasicAnimation *fadeInAnimation;
fadeInAnimation=[CABasicAnimation animationWithKeyPath:#"opacity"];
fadeInAnimation.repeatCount = 1;
fadeInAnimation.autoreverses = NO;
fadeInAnimation.fromValue = [NSNumber numberWithFloat:1.0];
fadeInAnimation.toValue = [NSNumber numberWithFloat:0.0];
CABasicAnimation *shrinkAnimation;
shrinkAnimation = [CABasicAnimation animationWithKeyPath:#"bounds.size"];
shrinkAnimation.repeatCount = 1;
shrinkAnimation.autoreverses = NO;
shrinkAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
shrinkAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(0, 0)];
aniGroupOFF = [[CAAnimationGroup animation] retain];
aniGroupOFF.delegate = self;
aniGroupOFF.duration = ANI_DURATION;
aniGroupOFF.animations = [NSArray arrayWithObjects:shrinkAnimation, fadeInAnimation, nil];
And the commit:
[self addAnimation:aniGroupOFF forKey:#"shrinkAndFade"];
self.opacity = 0.0;
Answer:
CABasicAnimation *shrinkAnimation;
shrinkAnimation = [CABasicAnimation animationWithKeyPath:#"transform"]; //use transform instead of bounds.size
shrinkAnimation.repeatCount = 1;
shrinkAnimation.autoreverses = NO;
shrinkAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
shrinkAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DScale(self.transform, 0.1, 0.1, 1.0)];
aniGroupOFF = [[CAAnimationGroup animation] retain];
aniGroupOFF.delegate = self;
aniGroupOFF.duration = ANI_DURATION;
aniGroupOFF.animations = [NSArray arrayWithObjects:shrinkAnimation, nil];
The easiest way to achieve this is to animate the keyPath "transform.scale" instead of "bounds.size".
If you stick with "bounds.size" you will need to implement layoutSublayers on layer A or layoutSublayersOfLayer:(CALayer*)aLayer on A's delegate and manually adjust B's size in that implementation.

Rotating a CALayer from a start angle

I want to rotate a layer continuously using byValue, but I can't make it work correctly.
I want to rotate by 6 degrees every second, to have a full rotation in 60 seconds.
If the initial rotation of the layer is 0, everything is OK.
The problem is when I try to set an initial fromValue. If I set the fromValue to 90 degrees, the animation will rotate from 90 to 90+6, then jump to 90+(90+6), animate, and jump again.
Any idea?
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithDouble:M_PI_2];
animation.byValue = [NSNumber numberWithDouble:6.0f*M_PI/180.0f];
animation.toValue = nil;
animation.fillMode = kCAFillModeForwards;
animation.cumulative = YES;
animation.additive = NO;
animation.repeatCount = 10000;
animation.removedOnCompletion = YES;
animation.duration = 1.0;
[myLayer addAnimation:animation forKey:#"transform"];
This works for me:
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath: #"transform"];
CATransform3D transform = CATransform3DMakeRotation (DegreesToRadians (90), 0, 0, 1);
animation.toValue = [NSValue valueWithCATransform3D: transform];
animation.duration = 60;
animation.cumulative = NO;
animation.repeatCount = 10000;
animation.removedOnCompletion = YES;