Image Zoom Scale is Not Resetting

So I have two buttons (which have images attached to them) in my view controller. When either is clicked there is a centered popup of that image.


The problem is, that the 1st button's image does not reset its zoom scale after use (the second does). So when you click on the image the second time, it is still zoomed in, and misaligned.


Here is the code for the zoom feature only:


//the popup window
@IBOutlet var imageView1: UIView!
@IBOutlet var imageView2: UIView!
//scroll view
@IBOutlet weak var scrollView1: UIScrollView!
@IBOutlet weak var scrollView2: UIScrollView!
//image
@IBOutlet weak var zoomImageView1: UIImageView!
@IBOutlet weak var zoomImageView2: UIImageView!
//background is dimmed when the popup window is active
@IBOutlet weak var backgroundButton: UIButton!

var button1Pressed = false
var button2Pressed = false

//resizes zoomed image when orientation changes
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
       
   if UIDevice.current.orientation.isLandscape{
       imageView1.center = self.view.center
       imageView2.center = self.view.center
       imageView1.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
       imageView2.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
       scrollView1.zoomScale = 1.0
       scrollView2.zoomScale = 1.0
           
   } else if UIDevice.current.orientation.isPortrait{
       imageView1.center = self.view.center
       imageView2.center = self.view.center
       imageView1.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
       imageView2.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
       scrollView1.zoomScale = 1.0
       scrollView2.zoomScale = 1.0
   }

}

override func viewDidLoad() {
    super.viewDidLoad()

    self.scrollView1.minimumZoomScale = 1.0
    self.scrollView1.maximumZoomScale = 6.0
    self.scrollView2.minimumZoomScale = 1.0
    self.scrollView2.maximumZoomScale = 6.0

}

//this might be the problem code, not sure how to fix it though
func viewForZooming(in scrollView: UIScrollView) -> UIView? {

    if button1Pressed == true {
        return self.zoomImageView1
    } else {
        return self.zoomImageView2
    }

}

//activates the 1st image
@IBAction func showImageView1(_ sender: Any) {
  
        animateIn1()
        button1Pressed = true
  
}

//activates the 2nd image
@IBAction func showImageView2(_ sender: Any) {
  
    animateIn2()
    button2Pressed = true
  
}

//closes either image
@IBAction func closeImageView(_ sender: Any) {
  
    animateOut()
    button1Pressed = false
    button2Pressed = false

}

func animateIn1() {
  
    self.scrollView1.zoomScale = 1.0
         
    self.view.addSubview(imageView1)
    imageView1.center = self.view.center
    imageView1.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    imageView1.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
    imageView1.alpha = 0
  
    self.backgroundButton.alpha = 0.7
  
    UIView.animate(withDuration: 0.4) {
        self.imageView1.alpha = 1
        self.imageView1.transform = CGAffineTransform.identity
    }
}

func animateIn2() {
  
    self.scrollView2.zoomScale = 1.0

    self.view.addSubview(imageView2)
    imageView2.center = self.view.center
    imageView2.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    imageView2.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
    imageView2.alpha = 0
  
    self.backgroundButton.alpha = 0.7
  
    UIView.animate(withDuration: 0.4) {
        self.imageView2.alpha = 1
        self.imageView2.transform = CGAffineTransform.identity
    }
}

func animateOut() {
  
    if button1Pressed == true {
         UIView.animate(withDuration: 0.3, animations: {
            self.imageView1.transform = CGAffineTransform(scaleX: 1, y: 1)
            self.imageView1.alpha = 0
          
            self.backgroundButton.alpha = 0
          
        }) { (success:Bool) in
           self.imageView1.removeFromSuperview()
        }
      
   } else if button2Pressed == true {
       UIView.animate(withDuration: 0.3, animations: {
            self.imageView2.transform = CGAffineTransform(scaleX: 1, y: 1)
            self.imageView2.alpha = 0
          
            self.backgroundButton.alpha = 0
          
        }) { (success:Bool) in
            self.imageView2.removeFromSuperview()
        }
    }
}


It's probably something simple.


Any help would be greatly appreciated.

Answered by Slavic Y in 255798022

I found the solution. The only change that was made is the if statement.


Instead of relying on which button is pressed, it checks which scrollView is active.


func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    if scrollView == scrollView1 { 
        return self.zoomImageView1 
    } else {
        return self.zoomImageView2  
    }
}

I looked rapidly at your code ; I think you should set the other button pressed to false


//activates the 1st image

@IBAction func showImageView1(_ sender: Any) {

        animateIn1()
        button1Pressed = true
        button2Pressed = false
}

//activates the 2nd image
@IBAction func showImageView2(_ sender: Any) {

    animateIn2()
    button2Pressed = true
    button1Pressed = false
}

otherwise, when you call viewForZooming, button1Pressed is still true


func viewForZooming(in scrollView: UIScrollView) -> UIView? {
  
    if button1Pressed == true {
        return self.zoomImageView1
    } else {
        return self.zoomImageView2
    }
  
}


Note : test can be written more simply as

if button1Pressed { }

I implemented your code, but still got the same issue. I believe my closeImageView function solves the problem of making the buttons pressed = false. Because you have to close one popup before opening another.


It's strange to me that the second image works perfectly but the 1st does not...

Where is viewForZooming called ?


Can you show self.zoomImageView1 and self.zoomImageView2


With just very partial view on the code it is a bit difficult to guess what happens.


Another way to find would be to log something each time image1 and image2 are accessed ; you will see why they behave differently.

I don't call viewForZooming from anywhere, but it's required to act with the delegate in order for the view to scale with zooming.


I updated the code and added all of the IBOutlets, and func traitCollectionDidChange. Although traitCollectionDidChange shouldn't be making the difference here.

Could you log (print) something each time image1 and image2 are accessed ; you will see why they behave differently.


For instance :


func viewForZooming(in scrollView: UIScrollView) -> UIView? {

    if button1Pressed == true {
         print("return zoomImageView1 ")
        return self.zoomImageView1
    } else {
          print("return zoomImageView2 ")  
          return self.zoomImageView2
    }

}

When I print inside viewForZooming, it spams the proper message a few times when the button is pressed, or when the image is being zoomed.


When I print inside animateIn1 and animateIn2, under:


self.scrollView1.zoomScale = 1.0


It also prints the right message as the buttons are pressed.


I also used print inside animateOut right under each if statement, and it closed the proper images...


I've tryed to use:


self.scrollView1.zoomScale = 1.0

inside animateOut under the button1Pressed if statement, and it did fix the zoom, but messed with the animation.

In doc, they explain that frame is undefined if transform is not identity


h ttps://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html

The

transform
property is used to animate or move the entire view in complex ways. For example, you would use a transform to rotate or scale the view. If the current transform is not the identity transform, the
frame
property is undefined and should be ignored.

Is it the case in your code ?

Yes, I use transform in order to give my imageViews a better animation. When the button is pressed, the imageView enlarges, and when closed, it shrinks.


So I guess that would be considered dealing with complex shapes.


I tryed messing with viewForZooming by adding:


if button1Pressed == true {
     return self.zoomImageView1
} else if button2Pressed == true {
     return self.zoomImageView2
} else {
     return nil
}


And what that did is make both buttons act the same, as in neither resizes back to the default 1.0, but keeps whatever zoom I exited the popup in. The difference is that they kept their zoomed in position. They weren't out of place as with previous code.


Not sure if progress..

Yes that's better, as buttonPressed can both be false. But they cannot both be true (correct ?)


The change you have just made has changed the behavior of button2 (you said:The problem is, that the 1st button's image does not reset its zoom scale after use (the second does))


So, could you try this :

if button1Pressed {
      self.imageView2.transform = CGAffineTransform(scaleX: 1, y: 1)           // reset button1
      return self.zoomImageView1
} else if button2Pressed  {
      self.imageView1.transform = CGAffineTransform(scaleX: 1, y: 1)            // reset button2
      return self.zoomImageView2
} else {
      self.imageView2.transform = CGAffineTransform(scaleX: 1, y: 1)           // reset button1
      self.imageView1.transform = CGAffineTransform(scaleX: 1, y: 1)            // reset button2 
      return nil
}

It is true that both can be false, but only one can be true.


I implemented your code, but it gives the same result as the code in my previous statement.


I also tryed to add '== true' to the if statements, and switching around 'imageView2' and imageView1' just to see what happens... But it did not make a difference.

I'm just guessing here, last try. Replace by identity ?


if button1Pressed {
      self.imageView2.transform = CGAffineTransform.identity           // reset button1
      return self.zoomImageView1
} else if button2Pressed  {
      self.imageView1.transform = CGAffineTransform.identity           // reset button2
      return self.zoomImageView2
} else {
      self.imageView2.transform = CGAffineTransform.identity           // reset button1
      self.imageView1.transform = CGAffineTransform.identity           // reset button2
      return nil
}

Still seems to be giving the same results as before.

If you could post the complete project, that would help understand what's going on. Otherwise, I must admit I have no more idea.

Can't really post the whole project. But thanks for taking your time to help. I do think progress was made. I'll keep tinkering with it, and will post the solution once there is one.

wish you good luck.


Don't forget to close the thread once you have a solution.

Image Zoom Scale is Not Resetting
 
 
Q