Rather than creating two UIImageViews
, it seems logical to simply change the image
of one view. If I do that, is there anyway of having a fade/cross dissolve between the two images rather than an instant switch?

- 69,473
- 35
- 181
- 253

- 16,765
- 45
- 140
- 253
10 Answers
It can be much simpler using the new block-based, UIKit animation
methods.
Suppose the following code is in the view controller, and the UIImageView you want to cross-dissolve is a subview of self.view addressable via the property self.imageView
Then all you need is:
UIImage * toImage = [UIImage imageNamed:@"myname.png"];
[UIView transitionWithView:self.imageView
duration:5.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.imageView.image = toImage;
} completion:nil]
Done.
And to do it in Swift, it's like so:
let toImage = UIImage(named:"myname.png")
UIView.transitionWithView(self.imageView,
duration:5,
options: UIViewAnimationOptions.TransitionCrossDissolve, animations: { self.imageView.image = toImage }, completion: nil)
Swift 3, 4 & 5
let toImage = UIImage(named:"myname.png")
UIView.transition(with: self.imageView,
duration: 0.3,
options: .transitionCrossDissolve,
animations: { self.imageView.image = toImage },
completion: nil)
-
3The other answers are correct but outdated (and/or overly verbose). – Steven Kramer Jul 14 '12 at 20:47
-
3It's not necessary to do the transition on the super view. I managed to make this work by specifying the UIImageView itself as the target. – Desmond Jan 05 '13 at 11:13
-
This does not work with iOS 6.0+ ?? Any one knows an alternative for iOS6? – Van Du Tran Jan 15 '13 at 19:21
-
@VanDuTran This works fine on iOS6. Just try it: https://github.com/algal/TrivialImageDissolveDemo . – algal Jan 17 '13 at 17:45
-
@Desmond Thanks for the correction. In fact calling it on self.view will also impose the specified animation duration on other subviews of self.view, such as a button. I will edit this later once I'm 100% sure I'm not missing some other factor. – algal Jan 17 '13 at 17:47
-
7@user577888 just a small thing. You should pass nil to the empty completion block. Blocks aren't function pointers (as denoted by the ^) and operate like an objective-c object. If you pass NULL, the compiler will interpret that as either 0 or (void *)0. If for some reason the underlying code for transitionWithView:... accidentally sends a message to the completion block (eg. [completion copy]) without checking its validity, this will lead to an error. So you should always use objective-c's nil when setting a block to be empty. – Mr. T Jan 26 '13 at 00:11
-
@Mr.T I think what you see is totally convincing on its merits, especially the point that blocks behave like objective-c objects so the absence of a block should be conveyed with nil not NULL. But: as near as I can tell, *all* of Apple's code examples pass NULL not nil when there's no block. Or did they change? – algal Feb 21 '13 at 10:08
-
3@Mr.T NULL and nil are identical in value. Both are defined to 0 and neither is ever likely to change. Thus, it is safe to use NULL anywhere you would or could use nil. – ashevin May 13 '13 at 08:21
-
@ashevin yea their values are both 0 but they're cast differently. NULL is either cast to 0 or (void *)0, and nil is cast as (id)0. Depending on your compiler, sending a message to NULL will cause a warning to occur, whereas sending a message to (id)0 will suppress that warning. So I tend to use nils whenever it's an objective-C object involved and use NULL whenever it's a c/c++ object involved. – Mr. T May 15 '13 at 18:19
-
1@Mr.T My point is that using one over the other will never cause a crash because at the compiled code level they are identical, and for practical reasons, always will be. Suppressing compiler warnings is a good idea, in general, but telling people it's an error to use NULL instead of nil is simply wrong. – ashevin May 17 '13 at 05:23
-
@Mr. T Passing NULL for a block is legal, has always been legal, and always will be legal. – hatfinch Nov 02 '13 at 13:38
-
No, it does not work on iOS 6 if you transition from a stretchable image to a non-stretchable image. ( @VanDuTran ) – hfossli Dec 05 '13 at 08:44
-
1+1 for the Swift bit. Looks like this is how we're going to have to write Cocoa-Touch answers from now on.. – user Jul 24 '14 at 20:37
-
I just lost an hour trying to figure out why my images never showed. Turns out I needed to call [imageView sizeToFit] after changing the image. FYI. – xaphod Nov 13 '14 at 15:44
-
1I had to wrap the whole thing in a `dispatch_after...` to make it work. Presumably to make sure, layout is completed before animating. – de. Jul 14 '15 at 14:01
-
1It's not working for me in in Swift 3 either. It animates the first time, however, when I call it 2nd time and on, it's just a change without the animation. – Gizmodo Mar 11 '17 at 05:52
-
I think we can also say the animation like.. animations:{self.imageView.image = self.imageview.image}..it is the same thing i think – Haileapp Dec 22 '17 at 12:09
-
I think we can also say the animation like.. animations:{self.imageView.image = self.imageview.image}..it is the same thing i think – Haileapp Dec 22 '17 at 12:09
Edit: there is a better solution from @algal below.
Another way to do this is by using predefined CAAnimation transitions:
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;
transition.delegate = self;
[self.view.layer addAnimation:transition forKey:nil];
view1.hidden = YES;
view2.hidden = NO;
See the View Transitions example project from Apple: https://developer.apple.com/library/content/samplecode/ViewTransitions/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007411
-
1Perfect! I add part of this code into SDWebImage's UIImageView (WebCache) category. – Autobots May 29 '13 at 04:06
-
@OutMan you might be better off using the newer method below by user577888. – Mirkules Jun 14 '13 at 22:16
-
I also am setting my image after a SDWebImages callback that way, but for some reason in my CollectionViewCell the image of the first cell, is initially the one from the last visible cell if all my cells update. I guess it's some kind of caching the presentationLayer or something?!? Any ideas what it could be? – Georg Feb 25 '14 at 12:37
-
For Swift 3.0.1 :
UIView.transition(with: self.imageView,
duration:0.5,
options: .transitionCrossDissolve,
animations: { self.imageView.image = newImage },
completion: nil)
Reference: https://gist.github.com/licvido/bc22343cacfa3a8ccf88

- 7,089
- 6
- 37
- 39
Yes what you say is absolutely correct and thats the way to do it. I wrote this method & always use this to Fade in my image. I deal with CALayer
for this. You need to import Core Animation for this.
+ (void)fadeInLayer:(CALayer *)l
{
CABasicAnimation *fadeInAnimate = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeInAnimate.duration = 0.5;
fadeInAnimate.repeatCount = 1;
fadeInAnimate.autoreverses = NO;
fadeInAnimate.fromValue = [NSNumber numberWithFloat:0.0];
fadeInAnimate.toValue = [NSNumber numberWithFloat:1.0];
fadeInAnimate.removedOnCompletion = YES;
[l addAnimation:fadeInAnimate forKey:@"animateOpacity"];
return;
}
You could do the opposite for Fade out an image. After it fades out. You just remove it from superview (which is UIImageView
). [imageView removeFromSuperview]
.

- 71,928
- 54
- 216
- 264
-
I add this code after set a image into UIImageView, it seem's there is a blink when starting animation. – Autobots May 29 '13 at 04:59
You could also package the fade-in feature in a subclass, so that you can then use it as a common UIImageView, as in the following example:
IMMFadeImageView *fiv=[[IMMFadeImageView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
[self.view addSubview:fiv];
fiv.image=[UIImage imageNamed:@"initialImage.png"];
fiv.image=[UIImage imageNamed:@"fadeinImage.png"]; // fades in
A possible implementation follows.
Note: the way you actually implement the fade-in in the setImage:
function can change, and could be one of the other excellent examples described in the other answers to this question — creating an additional on-the-fly UIImageView
as I'm doing here might be an unacceptable overhead in your specific situation.
IMMFadeImageView.h :
#import <UIKit/UIKit.h>
@interface IMMFadeImageView : UIImageView
@property (nonatomic,assign) float fadeDuration;
@end
IMMFadeImageView.m :
#import "IMMFadeImageView.h"
@implementation IMMFadeImageView
@synthesize fadeDuration;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.fadeDuration=1;
}
return self;
}
-(void)setImage:(UIImage *)newImage{
if(!self.image||self.fadeDuration<=0){
super.image=newImage;
} else {
UIImageView *iv=[[UIImageView alloc] initWithFrame:self.bounds];
iv.contentMode=self.contentMode;
iv.image=super.image;
iv.alpha=1;
[self addSubview:iv];
super.image=newImage;
[UIView animateWithDuration:self.fadeDuration delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
iv.alpha=0;
} completion:^(BOOL finished) {
[iv removeFromSuperview];
}];
}
}
The above code relies on a few assumptions (including ARC being enabled in your XCode project), is only intended as a proof of concept, and in the interest of clarity and focus, it stays relevant by omitting important unrelated code. Please don't just copy-paste it blindly.

- 8,432
- 1
- 35
- 33
I needed the transition to repeat indefinitely. It took a LOT of trial and error for this one but I finally got the end-result I was looking for. These are code snippets for adding image animation to a UIImageView in a UITableViewCell.
Here is the relevant code:
@interface SomeViewController ()
@property(nonatomic, strong) NSMutableArray *imagesArray;
@property(nonatomic, assign) NSInteger varietyImageAnimationIndex;
@property(nonatomic, assign) BOOL varietyImagesAnimated;
@end
@implementation SomeViewController
@synthesize imagesArray;
@synthesize varietyImageAnimationIndex;
@synthesize varietyImagesAnimated;
...
// NOTE: Initialize the array of images in perhaps viewDidLoad method.
-(void)animateImages
{
varietyImageAnimationIndex++;
[UIView transitionWithView:varietyImageView
duration:2.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
varietyImageView.image = [imagesArray objectAtIndex:varietyImageAnimationIndex % [imagesArray count]];
} completion:^(BOOL finished) {
[self animateImages];
}];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
[cell.imageView setImage:[imagesArray objectAtIndex:0]];
[self setVarietyImageView:cell.imageView];
if (! varietyImagesAnimated)
{
varietyImagesAnimated = YES;
[self animateImages];
}
...
return cell;
}

- 5,806
- 7
- 31
- 41
-
Hi I was wondering if you could add some more info on your [self setVarietyImageView:cell.imageView]; method as I can get the last cell to animate or all to animate but really fast, Thanks – gav Oct 05 '13 at 20:48
-
Hi Gav, "varietyImageView" is a weak reference in the view controller so that I can assign to cell.imageView and reference it later in method 'animateImages'. @property(nonatomic, weak) UIImageView *varietyImageView; You can make the images rotate faster by setting a shorter "duration" in "transitionWithView". Hopefully this is what you are asking. – Christopher Oct 06 '13 at 17:48
-
Hi Christopher thank you for the reply, I was wondering about the "setVarietyImageView:" I assume its some kind of void method that allows for reuse as I have only been able to animate the last cell. Again Thank you for replying, all the best Gav – gav Oct 06 '13 at 18:04
-
This method is generated using the standard "property" declaration. For example, @property(nonatomic, weak) UIImageView *varietyImageView. It's a "weak" reference as it refers to another local variable (the imageView of the table cell). I could have instead made a reference to the table cell and access the cell.imageView in method animateImages. I hope this helps. – Christopher Oct 08 '13 at 04:53
After playing around with UIView.transition()
and getting problems with .transitionCrossDissolve
option (I was trying to animate images changing inside one UIImageView and transition occurred instantly without animation) I found out that you just need to add one more option which is letting you animate properties changing inside the view (Swift 4.2):
UIView.transition(with: self.imageView,
duration: 1,
options: [.allowAnimatedContent, .transitionCrossDissolve],
animations: { self.imageView.image = newImage },
completion: nil)
In addition: if your have any subviews on your imageView, it will be redrawn as well and it could prevent animation. For example, I had subview with blur on my imageView and in that case animation doesn't work. So I just changed my view hierarchy and move blur to its own view and put it over imageView.

- 61
- 7
This is I think the shortest way of doing it. Create a UIView animation and commit it on your imageView.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[myImageView setAlpha:0.0];
[UIView commitAnimations];

- 2,037
- 19
- 38
By using the highlightedImage
property this can be made a bit more simple. Here's an example in Swift 3. First set both normal and highlighted image:
let imageView = UIImageView(image: UIImage(named: "image"), highlightedImage: UIImage(named: "highlightedImage"))
And when you want to change between those animated:
UIView.transition(with: imageView, duration: 0.3, options: .transitionCrossDissolve, animations: { self.imageView.isHighlighted = !self.imageView.isHighlighted}, completion: .none)

- 2,840
- 1
- 22
- 35
If you're using SDWebImage
, you're in luck. SDWebImage ver 4.3.0 onwards has inbuilt fade
& fade(duration:)
methods. DOC
imageView.sd_imageTransition = .fade //.fade(duration: 0.7)
let url = URL(string: "https://foo/bar.jpg")
imageView.sd_setImage(with: url)

- 7,016
- 5
- 54
- 92