Matt Kelly
Matt Kelly

Reputation: 1491

Swift - UIImageView zooms bigger than UIScrollView

I'm having a problem with pinch zooming a UIImageView which is set inside a UIScrollView. 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 UIScrollView. 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.

The following SO questions seem to be loosely related but I still couldn't resolve my problem after looking at them:

My UIScrollView 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 viewDidLoad() (and have added UIScrollViewDelegate to the top of my class). The UIImageView is created programmatically. I declare the image view at the top of the class as below:

class VCImageViewer: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var lblImageTitle: UILabel!
@IBOutlet weak var btnBack: UIButton!
@IBOutlet weak var scrollView: UIScrollView!

var imageView:UIImageView = UIImageView()  // <-- Image view

I then add the image view as a sub view of my UIScrollView with the follow line of code, called during viewDidLoad():

self.scrollView.addSubview(self.imageView)

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 viewDidLoad().

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()
            }

This confirms that the image has loaded correctly, hides a warning label I would display if it hadn't, and calls self.FormatImageViewerWithImage(), which is below:

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
}

I have also implemented scrollViewDidZoom with:

func scrollViewDidZoom(_ scrollView: UIScrollView) {
    self.CentreScrollViewContents()
}
func CentreScrollViewContents() {
    let boundsSize = self.scrollView.bounds.size
    var contentsFrame = self.imageView.frame
    if contentsFrame.size.width < boundsSize.width {
        contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2
    } else {
        contentsFrame.origin.x = 0
    }
    if contentsFrame.size.height < boundsSize.height {
        contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2
    } else {
        contentsFrame.origin.y = 0
    }
    self.imageView.frame = contentsFrame
}

and viewForZooming with:

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
    return self.imageView
}

I have seen previous questions (including some listed above) which suggested adding code to viewWillLayoutSubviews(), but I have not had any success with that, so my viewWillLayoutSubviews() is empty.

Can anyone see anything I am doing wrong?

Upvotes: 1

Views: 1230

Answers (1)

Mohamad Bachir Sidani
Mohamad Bachir Sidani

Reputation: 2099

Please change this line:

self.scrollView.clipsToBounds = false

to this line:

self.scrollView.clipsToBounds = true

Hope this helps!

Upvotes: 1

Related Questions