crossfade animation between two UIImages in objective-c doesn't fade out the first UIImage - iphone

I want to crossfade between two different UIImages but for a reason i cannot figure out my first UIImage stays when the second one fades in.
Here is the sourcecode of my animation (it does a lot more than just crossfading, but the crossfading is my only problem right now).
I need all of the three animations listed below to be executed at the same time.
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath,NULL,startPoint.x, startPoint.y);
CGPathAddLineToPoint(thePath, NULL, endPoint.x, endPoint.y);
CAKeyframeAnimation *positionAnimation =[CAKeyframeAnimation animationWithKeyPath:#"position"];
positionAnimation.path=thePath;
positionAnimation.duration=ti_duration;
positionAnimation.repeatCount=0;
positionAnimation.delegate = self;
positionAnimation.autoreverses=NO;
positionAnimation.fillMode=kCAFillModeForwards;
positionAnimation.removedOnCompletion = NO;
[self.layer addAnimation:positionAnimation forKey:s_direction];
CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:#"contents"];
crossFade.duration = ti_duration;
crossFade.fromValue = (id)img_startImage.CGImage;
crossFade.toValue = (id)img_transferImage.CGImage;
[self.iv_image.layer addAnimation:crossFade forKey:#"animateContentsToTransferState"];
[self.iv_image setImage:img_transferImage];
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.duration = ti_duration;
theGroup.repeatCount = 0;
theGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
theGroup.animations = [NSArray arrayWithObjects:/*positionAnimation,*/ crossFade, nil]; // you can add more
[self.layer addAnimation:theGroup forKey:#"move"];
[UIView beginAnimations:#"changeSize" context:nil];
[UIView setAnimationDuration:duration];
self.bounds = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.transferSize.width, self.transferSize.height);
[UIView commitAnimations];
The animation method containing this sourcecode is in a subclass of UIView. This subclass contains several UIImages and one UIImageView where the image to be displayed is contained in.
Have i forgotten some essential thing or why is my first image not fading away?
Can it be because it is animated from some other animation at the same time?
I hope someone can help me with this.
Greets
Maverick

Think of CAAnimations as operations applied to the CALayer. The animations current state do not change the layers original contents.
When the original state seems to snap back at the end of the animation it is actually just the animations operation being removed, and the real layers state is being revealed again.
What you need to do is to register a delegate for your animation, and change the actual self.layer.contents when the animation ends.
First:
crossFade.delegate = self;
Then implement:
- (void)animationDidStop:(CABasicAnimation *)animation finished:(BOOL)flag {
self.layer.contents = animation.toValue;
}

Try this code...It worked for me.
-(void)crossFadeImage{
CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:#"contents"];
crossFade.duration = 2.0;
crossFade.fromValue = img1.CGImage;
crossFade.toValue = img2.CGImage;
[self.background.layer addAnimation:crossFade forKey:#"animateContents"];
self.background.image = img2;
}

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!!!

Multiple CAAnimations On Different Views Simultaneously

I'm trying execute a couple of animations at the same time. One is transitioning from one uimageview to another and the other is animating translation.x of a label. The label resides on top of uiimageview.
But what I get is either translation working fine and transition happens immediately, or the transitioning -based on hidden property - also applies to my label which should only be shifted (it also goes from hidden to visible). I can't use caanimationgroup because they apply to different views.
//CAKeyFrameAnimation for sliding the label
...
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"transform.translation.x"];
NSArray *xValues = #[[NSNumber numberWithFloat:myLabel.bounds.origin.x],
[NSNumber numberWithFloat:myLabel.bounds.origin.x + screenHalf],
[NSNumber numberWithFloat:myLabel.bounds.origin.x + screenHalf * 4]];
[anim setValues:xValues];
NSMutableArray *timeFrames = [NSMutableArray array];
CGFloat timeStep = 1.0 / ([xValues count] - 1);
for (NSInteger i = 0; i < [xValues count]; i++)
{
[timeFrames addObject:[NSNumber numberWithFloat:timeStep * i]];
}
[anim setKeyTimes:timeFrames];
[anim setDuration:duration];
[anim setFillMode:kCAFillModeForwards];
[anim setRemovedOnCompletion:FALSE];
[myLabel.layer addAnimation:anim forKey:nil];
...
//Transitioning from uiimageview to another one
...
CATransition *transition = [CATransition animation];
[transition setDuration:duration];
[transition setType:kCATransitionFade];
//These two are uiimageviews i'm switching from and to
initial.hidden = TRUE;
next.hidden = FALSE;
//Initial and next are subviews of container which itself is a subview of viewcontroller's main view
[container.layer addAnimation:transition forKey:#""];
If I call the animations like above the transition occurs immediately and label slides across screen correctly. If I change the last line to:
[self.view.layer addAnimation:transition forKey:#""];
Then hidden animation also applies to myLabel. What is the fix for combining animations like above, and also more elaborately what is the cause?
I would wrap the entire code in a CATransaction to group the different CAAnimations into a single group.
Psuedo-code for using this with CAKeyFrameAnimation would look like:
[CATransaction begin];
// set completion block if you want
[CATransaction setCompletionBlock:^{ NSLog(#"I'm done"); }];
// start a keyframe animation
CAKeyframeAnimation *key1 = .....
// start another keyframe animation block
CAKeyframeAnimation *key2 = ......
// Maybe do a basic animation
CABasicAnimation *anim1 = .....
// close out all the animations and have them start
[CATransaction commit];

Display the Image like Fade In using CABasicAnimation

I am rotating the Image 360 clockwise using the CABasicAnimation, and the code which I am using is
CALayer* _caLayer = [CALayer layer];
_caLayer.contents = (id)_logo.CGImage;
_caLayer.frame = CGRectMake(65,158, 180,55);
[self.view.layer addSublayer:_caLayer];
CABasicAnimation* rotation;
rotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotation.fromValue = [NSNumber numberWithFloat:0];
rotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
rotation.duration = 1.4f;
//rotation.beginTime = CACurrentMediaTime() +1;
rotation.repeatCount = 2.0;
rotation.fillMode = kCAFillModeForwards;
[_caLayer addAnimation:rotation forKey:#"360"];
The animation is working fine.. But I cant figure out one thing. I want to start animate the image from smaller size and ends with the normal size. You have seen in movies like some newspapers will rotate fast and they fade in and finally we will see the paper in the screen fully. I am trying to do that way. I dont know how to do it, please !
You can use the following also, will works like a charm
[UIView beginAnimations:#"fade in" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
_imageView.alpha = 0.0;
_newImageView.alpha = 1.0;
[UIView commitAnimations];
Set the imageView frame before animation: [imageView setFrame: CGRectMake(your Frame)];
then keep on increasing the frame in the animation using a loop or something..

UIView animation to slide down

I'm trying to slide down an image in an UIImageView, but I don't know which combination of UIContentMode and animation property is the right one to make that happen.
The image should always have the same size and should not be streched... all I want is, that nothing is visible first and then the frame extends and reveals the image.
Maybe it's easier if you see what I mean:
So, it sounds rather easy, but what UIContentMode should I use for the UIImageView and what property should I animate? Thank you!
I took your lead and made a screencast as well. Was this what you had in mind?
I put the animation repeating indefinitely so it would be easier to capture with a video, but it can be started at the press of a button, as well as frozen in place, showing the popover and its contents, until reversed to be hidden again.
I used Core Animation for that, instead of animating a UIView, since I wanted to use the mask property of CALayer to hide the popover and reveal it with a sliding animation.
Here is the code I used (same as in the video):
- (void)viewDidLoad
{
// Declaring the popover layer
CALayer *popover = [CALayer layer];
CGFloat popoverHeight = 64.0f;
CGFloat popoverWidth = 200.0f;
popover.frame = CGRectMake(50.0f, 100.0f, popoverWidth, popoverHeight);
popover.contents = (id) [UIImage imageNamed:#"popover.png"].CGImage;
// Declaring the mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0, - popoverHeight, popoverWidth, popoverHeight);
maskLayer.backgroundColor = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f].CGColor;
// Setting the animation (animates the mask layer)
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"position.y"];
animation.byValue = [NSNumber numberWithFloat:popoverHeight];
animation.repeatCount = HUGE_VALF;
animation.duration = 2.0f;
[maskLayer addAnimation:animation forKey:#"position.y"];
//Assigning the animated maskLayer to the mask property of your popover
popover.mask = maskLayer;
[self.view.layer addSublayer:popover];
[super viewDidLoad];
}
NOTE: You have to import the QuartzCore framework into your project and write this line in your header file: #import <QuartzCore/QuartzCore.h>.
Tells if this works for you or if you need any more help setting this up.
Try this code.
Consider the UIImageView as imageView.
imageView.contentMode = UIViewContentModeScaleAspectFill;
CGRect imageRect = imageView.frame;
CGRect origImgRect = imageRect;
imageRect.size.height = 5;
imageView.frame = imageRect;
[UIView animateWithDuration:2.0
animations:^{imageView.rect = origImgRect;}
completion:^(BOOL finished){ }];

Animating resizing and moving UIView at the same time

I'd like to "Stretch" a UIView to the right side, meaning increase it's frame.size.width by foo pixels and at the same time decreasing it's frame.origin.x by foo pixels, using [UIView beginAnimations] syntax.
However, if I do that, when the animation begins the view immediately resizes, and then starts the animation for the origin.
CGRect currFrame = someView.frame;
currFrame.size.width += 100;
currFrame.origin.x -= 100;
[UIView beginAnimations:#"Anim1" context:nil];
someView.frame = currFrame;
[UIView setAnimationDuration:0.7];
[UIView commitAnimations];
I've also tried breaking the animation down to 2 parts but then I can't keep the right position in place.
Any help is much appreciated!
You might need to drop down to Core Animation and break this into two explicit animations:
CABasicAnimation *stetchAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
stetchAnimation.toValue = [NSNumber numberWithDouble:(someView.frame.size.width+100)/someView.frame.size.width];
CABasicAnimation *slideAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
slideAnimation.toValue = [NSNumber numberWithDouble:-100];
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = [NSArray arrayWithObjects:stetchAnimation,slideAnimation,nil];
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.duration = 0.7;
[someView.layer addAnimation:animationGroup forKey:#"animations"];