title: Swift - UIImageView zooms bigger than UIScrollView
body: <p>I'm having a problem with pinch zooming a <code>UIImageView</code> which is set inside a <code>UIScrollView</code>.  The image zooms in response to the user's pinch inputs, but the image zooms and gets bigger until it takes up the entire screen rather than staying inside the bounds of my <code>UIScrollView</code>.  I have had a look at a heap of different SO questions, articles and YouTube videos to try and find the source of the problem but haven't been able to find anything.</p>
  
  <p>The following SO questions seem to be loosely related but I still couldn't resolve my problem after looking at them:</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/questions/8978841/content-size-of-uiscrollview">content size of UIScrollView</a></li>
  <li><a href="https://stackoverflow.com/questions/19633843/uiscrollview-with-scaled-uiimageview-using-autolayout">UIScrollView with scaled UIImageView using autolayout</a></li>
  <li><a href="https://stackoverflow.com/questions/13324512/uiscrollview-squashes-uiimageview-image">UIScrollView squashes UIImageView image</a></li>
  <li><a href="https://stackoverflow.com/questions/27961884/swift-uiimageview-stretched-aspect">Swift UIImageView Stretched Aspect</a></li>
  <li><a href="https://stackoverflow.com/questions/30014241/uiimageview-pinch-zoom-swift">UIImageView pinch zoom swift</a></li>
  </ul>
  
  <p>My <code>UIScrollView</code> is created in my storyboard and I used layout constraints created in the interface builder to anchor it in place.  I set the scroll view's delegate to self in <code>viewDidLoad()</code> (and have added <code>UIScrollViewDelegate</code> to the top of my class).  The <code>UIImageView</code> is created programmatically.  I declare the image view at the top of the class as below:</p>
  
  <pre><code>class VCImageViewer: UIViewController, UIScrollViewDelegate {
  @IBOutlet weak var lblImageTitle: UILabel!
  @IBOutlet weak var btnBack: UIButton!
  @IBOutlet weak var scrollView: UIScrollView!
  
  var imageView:UIImageView = UIImageView()  // &lt;-- Image view
  </code></pre>
  
  <p>I then add the image view as a sub view of my <code>UIScrollView</code> with the follow line of code, called during <code>viewDidLoad()</code>:</p>
  
  <pre><code>self.scrollView.addSubview(self.imageView)
  </code></pre>
  
  <p>After adding the image view to the scroll view, I load an image into the image view.  I fetch the image from a URL, and load it in using the following code.  Again, this is called in <code>viewDidLoad()</code>.</p>
  
  <pre><code>self.imageView.image = UIImage(data: data)
              self.imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: (self.imageView.image?.size)!)
              if self.imageView.image != nil {
                  self.lblError.isHidden = true
                  self.FormatImageViewerWithImage()
              }
  </code></pre>
  
  <p>This confirms that the image has loaded correctly, hides a warning label I would display if it hadn't, and calls <code>self.FormatImageViewerWithImage()</code>, which is below:</p>
  
  <pre><code>func FormatImageViewerWithImage() {
      // Constraints
      let constraintImageViewTop:NSLayoutConstraint = NSLayoutConstraint(item: self.imageView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.scrollView, attribute: NSLayoutAttribute.top, multiplier: 1, constant: 0)
      let constraintImageViewBottom:NSLayoutConstraint = NSLayoutConstraint(item: self.imageView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.scrollView, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)
      let constraintImageViewLeft:NSLayoutConstraint = NSLayoutConstraint(item: self.imageView, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: self.scrollView, attribute: NSLayoutAttribute.left, multiplier: 1, constant: 0)
      let constraintImageViewRight:NSLayoutConstraint = NSLayoutConstraint(item: self.imageView, attribute: NSLayoutAttribute.right, relatedBy: NSLayoutRelation.equal, toItem: self.scrollView, attribute: NSLayoutAttribute.right, multiplier: 1, constant: 0)
      self.view.addConstraints([constraintImageViewTop, constraintImageViewBottom, constraintImageViewLeft, constraintImageViewRight])
  
      self.scrollView.contentSize = self.imageView.image!.size
      self.scrollView.clipsToBounds = false
      let scrollViewFrame = scrollView.frame
      let scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width
      let scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height
      let minScale = min(scaleWidth, scaleHeight)
      self.scrollView.minimumZoomScale = minScale
  
      self.scrollView.maximumZoomScale = 1.0
      self.scrollView.zoomScale = minScale
  }
  </code></pre>
  
  <p>I have also implemented <code>scrollViewDidZoom</code> with:</p>
  
  <pre><code>func scrollViewDidZoom(_ scrollView: UIScrollView) {
      self.CentreScrollViewContents()
  }
  func CentreScrollViewContents() {
      let boundsSize = self.scrollView.bounds.size
      var contentsFrame = self.imageView.frame
      if contentsFrame.size.width &lt; boundsSize.width {
          contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2
      } else {
          contentsFrame.origin.x = 0
      }
      if contentsFrame.size.height &lt; boundsSize.height {
          contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2
      } else {
          contentsFrame.origin.y = 0
      }
      self.imageView.frame = contentsFrame
  }
  </code></pre>
  
  <p>and <code>viewForZooming</code> with:</p>
  
  <pre><code>func viewForZooming(in scrollView: UIScrollView) -&gt; UIView? {
      return self.imageView
  }
  </code></pre>
  
  <p>I have seen previous questions (including some listed above) which suggested adding code to <code>viewWillLayoutSubviews()</code>, but I have not had any success with that, so my <code>viewWillLayoutSubviews()</code> is empty.</p>
  
  <p>Can anyone see anything I am doing wrong?</p>