ios CoreAnimation - ios

I'm trying to skew an object cards it's an UIView I'm doing :
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:DEPLACEMENT_ANIMATION_DUREE_SECONDES_DROITE];
scene.carte17.layer.position = positionInit;
if (scene.carte17.angleCarte == 15.f) {
scene.carte17.transform = CGAffineTransformRotate(scene.carte17.transform, degreesToRadians(30));
scene.carte17.angleCarte = 45.f;
}
[UIView commitAnimations];
And it's working ! My card incline to 30° and it's good. I'm playing with setAnimationDuration to control the speed.
I would like to use CoreAnimation and kCAMediaTimingFunctionEaseInEaseOut to have a better animation but I'm not ok to do the same think with core animation I'm trying this :
[CATransaction begin];
[CATransaction setAnimationDuration:.5f];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
scene.carte17.layer.position = positionInit;
if (scene.carte17.angleCarte == 15.f) {
CABasicAnimation *animation;
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.fromValue = [NSNumber numberWithFloat:0.0];
animation.toValue = [NSValue valueWithCGAffineTransform:CGAffineTransformRotate(scene.carte17.transform, degreesToRadians(30))];
animation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
animation.delegate = self;
[scene.carte17.layer addAnimation:animation forKey:#"rotationAnimation"];
scene.carte17.angleCarte = 45.f;
}
[CATransaction commit];
But it's not working ... Could you help me please !

Why not just call this:
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
But that is an overkill since UIViewAnimationCurveEaseInOut is the default value.

Related

Creating Animation for search

I am writing an animation for my search button, so when the user clicks on search I want to make a transition on my button and then move it to left and push the search view on it's back. I am trying to use the following code:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.repeatDuration = 1000;
animation.duration = 30;
animation.additive = YES;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
animation.fromValue = [NSNumber numberWithFloat:0];
animation.toValue = [NSNumber numberWithFloat:360];
[self.SearchButton.layer addAnimation:animation forKey:#"rotationAnimation"];
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
[UIView animateWithDuration:0.6 delay:2 options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.SearchButton setFrame:CGRectMake(self.slideMenuButton.frame.origin.x, self.slideMenuButton.frame.origin.y, self.SearchButton.frame.size.width, self.SearchButton.frame.size.height)];
[UIView animateWithDuration:0.6 delay:10.f options:UIViewAnimationOptionCurveEaseIn animations:^{
[self.navigationController presentViewController:Search animated:YES completion:nil];
}completion:^(BOOL finished) {
[self.SearchButton setFrame:CGRectMake(searchOrigin.x, searchOrigin.y, self.SearchButton.frame.size.width, self.SearchButton.frame.size.height)];
}];
} completion:^(BOOL finished) {
[self.SearchButton.layer removeAnimationForKey:#"rotationAnimation"];
}];
}];
}
Each animation is working correctly but I want them to follow each other so the feeling of movements be good. It means I want the button to do a transition and then move to the new point and the new view push to my view by following that.
It would be appreciated if you help me or give me any idea so I can implement that.

Add a bounce effect to a flip animation

I animated a flip for a pie chart I have. Here is my code"
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:0.5];
scaleAnimation.duration = 1.0f;
scaleAnimation.removedOnCompletion = NO;
[self.pieChart addAnimation:scaleAnimation forKey:#"scale"];
animationDidStop:finished:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
animation.fromValue = [NSNumber numberWithFloat:0.5];
animation.toValue = [NSNumber numberWithFloat:1.0];
animation.duration = 1.0f;
[self.pieChart addAnimation:animation forKey:#"scale"];
How can I add a bounce effect to the second animation? (The animation in animationDidStop:finished:)
Go with a CAKeyFrameAnimation instead of two CABasicAnimation:
CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale.x"];
scaleAnimation.keyTimes = #[#(0), #(0.5), #(0.9), #(1)];
scaleAnimation.values = #[#(1.0), #(0.5), #(1.1), #(1.0)];
scaleAnimation.duration = 1.0f;
scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
With keyTimes and values, you can specify multiple stances in your animation. Here, I made it start with a scale of 1, animating to a scale of 0.5 (your first animation values), then 1.1 (an overshoot to create a "bounce") and finally 1 (your second animation values). Tweak those to your liking!
If you want to do this animation in two parts, you can keep your first animation, then start a CAKeyFrameAnimation in the animationDidStop:finished: similar to this instead:
CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale.x"];
scaleAnimation.keyTimes = #[#(0), #(0.8), #(1)];
scaleAnimation.values = #[#(0.5), #(1.1), #(1.0)];
scaleAnimation.duration = 1.0f;
scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
If you instead want to use UIView animation blocks, you'll need to do something similar to this:
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.squareView.transform = CGAffineTransformMakeScale(0.5, 1);
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:0 animations:^{
self.squareView.transform = CGAffineTransformIdentity;
} completion:nil];
}];
You will probably want to play with the params to tweak the animation.

Converting code from CABasicAnimation

I have a animation code that is written using CABasicAnimation just as following:
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"position"];
[anim setDelegate:self];
anim.fromValue = [NSValue valueWithCGPoint:img.center];
if (newValue == 0) {
imgCentre.y = centerStart.y - 11 * kCounterDigitDiff;
anim.toValue = [NSValue valueWithCGPoint:imgCentre];
} else
anim.toValue = [NSValue valueWithCGPoint:imgCentre];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.duration = 0.3;
[img.layer addAnimation:anim forKey:#"rollLeft"];
img.frame = frame;
Due to some reason I wish to apply same animation but by using following type of approach:
[UIView animateWithDuration:0.3 delay:0.0 options:(UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseOut) animations:^{
...
} completion:^(BOOL finished) {
...
}
What I come up with is like following:
[img setCenter:imgCentre];
[UIView animateWithDuration:0.3 delay:0.0 options:(UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseOut) animations:^{
if (newValue == 0) {
CGPoint newPoint= CGPointMake(imgCentre.x, centerStart.y - 11 * kCounterDigitDiff);
[img setCenter:newPoint];
} else{
[img setCenter:imgCentre];
}
} completion:^(BOOL finished) {
// animation completion code
}];
img.frame = frame;
Overall things look good but I am a little bit pessimistic about the conversion? is there something that i have missed?
You've got the right idea. However, unlike with CAAnimations, you don't have to set the properties to the end value. The UIView animation call takes care of all that for you.
UIView animation is generally easier and more intuitive to use than CAAnimation.

iOS animation with duration and autoreverse

I am animating an UIImageView with the UIView block API. My animation fades the UIImageView In and Out continuously. How can I animate this only for a specific time duration ?
I have put up this piece of code
float tempDuration = 5.0;
[UIView animateWithDuration:tempDuration
delay:0
options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction
animations:^{
_imageView.alpha = 1;
}
completion:nil];
First of all allow me to introduce an article that is awesome to understand some features of the animations:
Controlling Animation Timming
In this article you have a part that shows what you want.
You want something like this:
Therefore you can configure that in the following way:
-(void) animateImageView:(UIImageView*) imageView
withDuration:(int) duration
withRepeatCount: (int) repeatCount {
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnim.fromValue = #1.0;
opacityAnim.toValue = #0.0;
opacityAnim.autoreverses = YES;
opacityAnim.duration = duration/2.0/repeatCount;
opacityAnim.removedOnCompletion = YES;
opacityAnim.repeatCount = repeatCount;
[imageView.layer addAnimation:opacityAnim forKey:nil];
}
This way you guarantee that your animation will always be 5 seconds and you can tune in the number of repetitions.
Maybe you could try CABasicAnimation instead if [UIView animateWithDiration: ... ]
it should be something like this:
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.0];
opacityAnim.autoreverses = YES;
opacityAnim.duration = duration;
opacityAnim.removedOnCompletion = YES;
opacityAnim.repeatCount = 5;
[imageView.layer addAnimation:opacityAnim forKey:nil];
You can do the following changes to do your work.
- (void)animateImageView{
static int animcount = 1;
float tempDuration = 1.0;
[UIView animateWithDuration:tempDuration
delay:0
options: UIViewAnimationOptionAutoreverse
animations:^{
self.imgView.alpha = 1;
}
completion:^(BOOL finished) {
if(finished && animcount<5){
animcount+=1;
[self animateImageView];
}
else if (finished && animcount==5){
[self.imgView.layer removeAllAnimations];
}
}];
}

How can I replace CGAffineTransform scale and alpha animations using CABasicAnimations and Auto Layout?

As far as I can see, Apple wants us to move away from CGAffineTransform animations and into animations using:
myView.layoutConstraint.constant = someNewValue;
[myView layoutIfNeeded];
for animations that involve a translation of a view.
It also seems we should be now using CABasicAnimation animations for scale and rotation (and sometimes opacity) because it animates the view's layer and not the view and in doing so, plays nicely with auto layout.
I used the following code to apply an opacity and scale animation that worked beautifully:
[UIView animateWithDuration:0.1f animations:^{
// first animation
self.myMeButton.alpha = 1;
self.myMeButton.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.2f animations:^{
// second animation
self.myButton.transform = CGAffineTransformMakeScale(1, 1);
}];
}];
Of course auto layout plays havoc with the scale animation and so I am trying to find an alternative way to do it. So far, I have come up with this:
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
// code for when animation completes
self.pickMeButton.alpha = 1;
CABasicAnimation *scaleDown = [CABasicAnimation animationWithKeyPath:#"scale"];
scaleDown.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
scaleDown.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
scaleDown.duration = 0.1;
[self.myButton.layer addAnimation:scaleDown forKey:nil];
}];
// describe animations:
CABasicAnimation* scaleUp = [CABasicAnimation animationWithKeyPath:#"scale"];
scaleUp.autoreverses = NO;
scaleUp.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
scaleUp.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
CABasicAnimation *fadeAnim = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeAnim.fromValue=[NSNumber numberWithDouble:0.0];
fadeAnim.toValue=[NSNumber numberWithDouble:1.0];
// Customization for all animations:
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 0.2f;
group.repeatCount = 1;
group.autoreverses = NO;
group.animations = #[scaleUp, fadeAnim];
// add animations to the view's layer:
[self.myButton.layer addAnimation:group forKey:#"allMyAnimations"];
} [CATransaction commit];
As you can see the code almost 3 times as long as before and the animation on the device is noticeably less 'smooth' than it was previously.
Is there any way to do this better?
Thanks in advance for your response.
EDIT: This seems to have done the trick in that the animations are smooth, but I still feel like the code for this could be a lot more succinct.
[UIView animateWithDuration:0.2f animations:^{
self.pickMeButton.alpha = 1;
CABasicAnimation* scaleUp = [CABasicAnimation animationWithKeyPath:#"transform"];
scaleUp.duration = 0.2;
scaleUp.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1)];
scaleUp.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1)];
[self.pickMeButton.layer addAnimation:scaleUp forKey:nil];
}completion:^(BOOL finished) {
CABasicAnimation* scaleDown = [CABasicAnimation animationWithKeyPath:#"transform"];
scaleDown.duration = 0.1;
scaleDown.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1)];
scaleDown.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
[self.pickMeButton.layer addAnimation:scaleDown forKey:nil];
}];
I don't know why you want to do it with CABasicAnimation for scale. You can do it like you mention at the top of your question. Set a new value for the view's width and height constraint constant values and then use [myView layoutIfNeeded] inside animateWithDuration. If the view doesn't have height and width constraints, but has constants to the top and bottom and/or left and right edges of the superview, change those values instead.

Resources