0
votes

I have an image in the navigation bar of a ViewController created in storyboard and an outlet property for the image and would like to animate a transition to another image. The view controller is launched modally using a transition.

I have no problem animating fading of the image by changing its alpha value. However, if I change the image rather than fade it, there is no animation. Instead, the new image is visible as soon as the page loads. This is true whether I put the animation code in viewDidLoad or viewWillAppear. I would like this animation to only take place once when the view loads, however, I tried it in viewWillAppear just to see if I could get the effect at all.

Here is my code

// in viewdidload or viewwillappear
   let newImage = UIImage(named: "headshot.png")
    UIView.transition(with: self.imageView,
                      duration:0.5,
                      options: .transitionCrossDissolve,
                      animations: { self.ImageView.image = newImage },
                      completion: nil)

Is there something special about animating an image in a navigation bar relative to a regular view? Or what do I need to do to animate the change of the image in a navigation bar?

1

1 Answers

0
votes

The reason why your image is not animating is because from the compiler's perspective, replacing an image with another (just like inserting an image), is an atomic action. This means that self.ImageView.image = newImage is a line that happens in a single step. That is, at any point in time, your imageView either has newImage as its image property, or it doesn't. Changes in state that happen atomically like that cannot be animated over time.

Another way to look at it is that in order to change the duration of your animation to 0.5 seconds (instead of performing this action atomically in a single step), the XCode compiler would have to literally place the image in your imageView in bits and pieces over the 0.5 seconds. Clearly, this is undefined behaviour. How does the compiler know which parts of the image to place on the screen at what time?

A simple solution to your problem is to have two separate imageViews - one of which starts out as transparent - that are placed in the exact same place on your screen. Each one of the imageViews will have a separate image, and you can transition between those two images by simply fading out one image and then fading in the other, like so:

class viewController: UIViewController {
    let imageView1 = UIImageView("headshot1.png")
    let imageView2 = UIImageView("headshot2.png")

    override viewDidLoad() {
        super.viewDidLoad()

        /* add imageViews to your view and place them both 
           in the middle of the screen */
        imageView1.translatesAutoresizingMaskIntoConstraints = false
        imageView1.alpha = 1.0
        self.addSubview(imageView1)

        /* notice that this imageView is completely transparent */
        imageView2.translatesAutoresizingMaskIntoConstraints = false
        imageView2.alpha = 0.0
        self.addSubview(imageView2)

        /* place both imageViews in the middle of your screen,
           with imageView1 completely visible and imageView2
           completely transparent */
        imageView1.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        imageView1.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

        imageView2.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        imageView2.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

        // fade out first imageView
        UIView.animate(withDuration: 0.25) {
        imageView1.alpha = 0.0
        }

        // fade in second imageView
        UIView.animate(withDuration: 0.25) {
        imageView2.alpha = 1.0
        }
    }
}

You could also use your transition function instead of my animate function - the logic is virtually the same.