228

I have an UIImageView with an image. Now I have a completely new image (graphic file), and want to display that in this UIImageView. If I just set

myImageView.image = newImage;

the new image is visible immediately. Not animatable.

I want it to nicely fade into the new image. I thought maybe there's a better solution than just creating a new UIImageView on top of that and blending with animation?

Bhavesh Nayi
  • 3,626
  • 1
  • 27
  • 42
dontWatchMyProfile
  • 45,440
  • 50
  • 177
  • 260
  • http://stackoverflow.com/questions/7638831/fade-dissolve-when-changing-uiimageviews-image/38350024#38350024 – Kumar KL Jul 13 '16 at 11:17

15 Answers15

383
[UIView transitionWithView:textFieldimageView
                  duration:0.2f
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    imageView.image = newImage;
                } completion:nil];

is another possibility

MarkHim
  • 5,686
  • 5
  • 32
  • 64
Ilker Baltaci
  • 11,644
  • 6
  • 63
  • 79
  • 1
    simple and opens up a whole range of other animation effects between the images. – So Over It Oct 06 '13 at 17:28
  • 1
    Has the same problem that @hfossli mentioned regarding frame changes. Animation would be sluggish if layouts are changed during that. – Geva Jul 01 '14 at 11:59
  • 1
    This is the best solution, because it can be combined with other animations. – kelin Jun 17 '15 at 07:35
264

I am not sure if you can animate UIViews with fade effect as it seems all supported view transitions are defined in UIViewAnimationTransition enumeration. Fading effect can be achieved using CoreAnimation. Sample example for this approach:

#import <QuartzCore/QuartzCore.h>
...
imageView.image = [UIImage imageNamed:(i % 2) ? @"3.jpg" : @"4.jpg"];

CATransition *transition = [CATransition animation];
transition.duration = 1.0f;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionFade;

[imageView.layer addAnimation:transition forKey:nil];
Vladimir
  • 170,431
  • 36
  • 387
  • 313
  • 2
    Your code worked perfectly when going from one image to another. Do you know how to make it work with automatic animation of images in a UIImageView (animationImages property) ? – CedricSoubrie Feb 25 '11 at 13:40
  • You can try to use CAKeyFrameAnimation for layer's content property, not sure though if the effect will be the same. Or set animation delegate and in delegate callback function start animating to the next image when previous animation finishes. – Vladimir Feb 25 '11 at 13:42
  • 2
    This is definitely simpler than manually crossfading a separate image view. Thanks! – Kevlar Aug 23 '12 at 18:55
  • Well.. If the imageviews frame changes then it stays in its same position.. thats a deal breaker! – hfossli Sep 26 '12 at 16:17
  • @Fossli, you mean when frame changes during animation? That's a different question then – Vladimir Sep 26 '12 at 16:20
202

In the words of Michael Scott, keep it simple stupid. Here is a simple way to do this in Swift 3 and Swift 4:

UIView.transition(with: imageView,
                  duration: 0.75,
                  options: .transitionCrossDissolve,
                  animations: { self.imageView.image = toImage },
                  completion: nil)
Zia
  • 14,622
  • 7
  • 40
  • 59
44

Here is one example in Swift that will first cross dissolve a new image and then add a bouncy animation:

var selected: Bool {
  willSet(selected) {
    let expandTransform:CGAffineTransform = CGAffineTransformMakeScale(1.15, 1.15);
    if (!self.selected && selected) {
      UIView.transitionWithView(self.imageView,
        duration:0.1,
        options: UIViewAnimationOptions.TransitionCrossDissolve,
        animations: {
          self.imageView.image = SNStockCellSelectionAccessoryViewImage(selected)
          self.imageView.transform = expandTransform
        },
        completion: {(finished: Bool) in
          UIView.animateWithDuration(0.4,
            delay:0.0,
            usingSpringWithDamping:0.40,
            initialSpringVelocity:0.2,
            options:UIViewAnimationOptions.CurveEaseOut,
            animations: {
              self.imageView.transform = CGAffineTransformInvert(expandTransform)
            }, completion:nil)
      })
    }
  }
}

var imageView:UIImageView

If imageView is correctly added to the view as a subview, toggling between selected = false to selected = true should swap the image with a bouncy animation. SNStockCellSelectionAccessoryViewImage just returns a different image based on the current selection state, see below:

private let SNStockCellSelectionAccessoryViewPlusIconSelected:UIImage = UIImage(named:"PlusIconSelected")!
private let SNStockCellSelectionAccessoryViewPlusIcon:UIImage = UIImage(named:"PlusIcon")!

private func SNStockCellSelectionAccessoryViewImage(selected:Bool) -> UIImage {
  return selected ? SNStockCellSelectionAccessoryViewPlusIconSelected : SNStockCellSelectionAccessoryViewPlusIcon
}

The GIF example below is a bit slowed down, the actual animation happens faster:

                                       UIImageView bounce animation Gif

Zorayr
  • 23,770
  • 8
  • 136
  • 129
27

Swift 5 extension:

extension UIImageView{
    func setImage(_ image: UIImage?, animated: Bool = true) {
        let duration = animated ? 0.3 : 0.0
        UIView.transition(with: self, duration: duration, options: .transitionCrossDissolve, animations: {
            self.image = image
        }, completion: nil)
    }
}
 
Li Jin
  • 1,879
  • 2
  • 16
  • 23
18

Code:

var fadeAnim:CABasicAnimation = CABasicAnimation(keyPath: "contents");

fadeAnim.fromValue = firstImage;
fadeAnim.toValue   = secondImage;
fadeAnim.duration  = 0.8;         //smoothest value

imageView.layer.addAnimation(fadeAnim, forKey: "contents");

imageView.image = secondImage;

Example:

UIImageView Example from code

Fun, More Verbose Solution: (Toggling on a tap)

    let fadeAnim:CABasicAnimation = CABasicAnimation(keyPath: "contents");

    switch imageView.image {
        case firstImage?:
            fadeAnim.fromValue = firstImage;
            fadeAnim.toValue   = secondImage;
            imageView.image    = secondImage;
        default:
            fadeAnim.fromValue = secondImage;
            fadeAnim.toValue   = firstImage;
            imageView.image    = firstImage;
    }

    fadeAnim.duration = 0.8;

    imageView.layer.addAnimation(fadeAnim, forKey: "contents");
J-Dizzle
  • 4,861
  • 4
  • 40
  • 50
12

Try this:

_imageView.image = image;
[_imageView.layer addAnimation:[CATransition animation] forKey:kCATransition];
Tankista
  • 1,685
  • 17
  • 26
8

With Swift 3

extension UIImageView{   
 var imageWithFade:UIImage?{
        get{
            return self.image
        }
        set{
            UIView.transition(with: self,
                              duration: 0.5, options: .transitionCrossDissolve, animations: {
                                self.image = newValue
            }, completion: nil)
        }
    }
}

Usage:

myImageView.imageWithFade = myImage
M.Nadeeshan
  • 251
  • 4
  • 8
6

Why not try this.

NSArray *animationFrames = [NSArray arrayWithObjects:
  [UIImage imageWithName:@"image1.png"],
  [UIImage imageWithName:@"image2.png"], 
  nil];

UIImageView *animatedImageView = [[UIImageView alloc] init];
animatedImageView.animationImages = animationsFrame;
[animatedImageView setAnimationRepeatCount:1];
[animatedImageView startAnimating];

A swift version:

let animationsFrames = [UIImage(named: "image1.png"), UIImage(named: "image2.png")]
let animatedImageView = UIImageView()
animatedImageView.animationImages = animationsFrames
animatedImageView.animationRepeatCount = 1
animatedImageView.startAnimating()
William Hu
  • 15,423
  • 11
  • 100
  • 121
6

Swift 4 This is just awesome

  self.imgViewPreview.transform = CGAffineTransform(scaleX: 0, y: 0)
          UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
              self.imgViewPreview.image = newImage
              self.imgViewPreview.transform = .identity
          }, completion: nil)
Gurjinder Singh
  • 9,221
  • 1
  • 66
  • 58
5
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"contents"];
fadeAnim.fromValue = (__bridge id)imageView.image.CGImage;
fadeAnim.toValue = (__bridge id)[UIImage imageNamed:@"newImage.png"].CGImage;
fadeAnim.duration = 2.0;
[imageView.layer addAnimation:fadeAnim forKey:@"contents"];
imageView.layer.contents = (__bridge id)[UIImage imageNamed:@"newImage.png"].CGImage;
kas-kad
  • 3,736
  • 1
  • 26
  • 45
3

There are a few different approaches here: UIAnimations to my recollection it sounds like your challenge.

Edit: too lazy of me:)

In the post, I was referring to this method:

[newView setFrame:CGRectMake( 0.0f, 480.0f, 320.0f, 480.0f)]; //notice this is OFF screen!
[UIView beginAnimations:@"animateTableView" context:nil];
[UIView setAnimationDuration:0.4];
[newView setFrame:CGRectMake( 0.0f, 0.0f, 320.0f, 480.0f)]; //notice this is ON screen!
[UIView commitAnimations];

But instead of animation the frame, you animate the alpha:

[newView setAlpha:0.0]; // set it to zero so it is all gone.
[UIView beginAnimations:@"animateTableView" context:nil];
[UIView setAnimationDuration:0.4];
[newView setAlpha:0.5]; //this will change the newView alpha from its previous zero value to 0.5f
[UIView commitAnimations];
Community
  • 1
  • 1
RickiG
  • 11,380
  • 13
  • 81
  • 120
2

Vladimir's answer is perfect, but anyone like me who is looking for swift solution

This Solution is Worked for swift version 4.2

var i = 0
    func animation(){
        let name = (i % 2 == 0) ? "1.png" : "2.png"
        myImageView.image = UIImage.init(named: name)
        let transition: CATransition = CATransition.init()
        transition.duration = 1.0
        transition.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
        transition.type = .fade
        myImageView.layer.add(transition, forKey: nil)
        i += 1
    }

You can call this method from anywhere. It will change the image to next one(image) with animation.

For Swift Version 4.0 Use bellow solution

var i = 0
    func animationVersion4(){
        let name = (i % 2 == 0) ? "1.png" : "2.png"
        uiImage.image = UIImage.init(named: name)
        let transition: CATransition = CATransition.init()
        transition.duration = 1.0
        transition.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
        transition.type = kCATransitionFade
        uiImage.layer.add(transition, forKey: nil)
        i += 1
    }
Saleh Enam Shohag
  • 1,039
  • 1
  • 12
  • 23
2

As of iOS 5 this one is far more easy:

[newView setAlpha:0.0];
[UIView animateWithDuration:0.4 animations:^{
    [newView setAlpha:0.5];
}];
Borut Tomazin
  • 8,041
  • 11
  • 78
  • 91
  • 4
    That does not help the original problem, which is that you have an image displayed already, and want to cross-fade to a new image... – Kendall Helmstetter Gelner Aug 19 '12 at 18:11
  • 4
    right .. this answer does not solve the question. The question was not how do fade in the imageview but to fade from an old image to a new image. Animation blocks were introduced in iOS 4. – Bastian Sep 05 '12 at 08:16
0

Swift 5:

When deal with collectionView. Reloading only 1 item or several items with animation. I try some different animation options when changing cell image, no difference, so I don't indicate animation name here.

UIView.animate(withDuration: 1.0) { [weak self] in
                guard let self = self else { return print("gotchya!") }
                self.collectionView.reloadItems(at: [indexPath])
            }
Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32