UIImageView pinch zoom swift

SwiftUiimageviewUipinchgesturerecognizer

Swift Problem Overview


I was hoping someone could help me out. I am trying to allow a user to pinch zoom on a UIImageView(with a max and min level allowed). But for some reason the it does not work right. The image zooms a little then just bounces back. Thank you.

here is the zoom func

func zoom(sender:UIPinchGestureRecognizer) {
    
    
    if sender.state == .Ended || sender.state == .Changed {
        
        let currentScale = self.view.frame.size.width / self.view.bounds.size.width
        var newScale = currentScale*sender.scale
        
        if newScale < 1 {
            newScale = 1
        }
        if newScale > 9 {
            newScale = 9
        }
        
        let transform = CGAffineTransformMakeScale(newScale, newScale)
        
        self.imageView?.transform = transform
        sender.scale = 1
        
    }
    
}

Swift Solutions


Solution 1 - Swift

UIImageView pinch zoom with UIScrollView || image zooming ios in swift 3 and Xcode 8 letter Youtube video URL

set uiscrollview Delegate in storyboard enter image description here

 class PhotoDetailViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var imgPhoto: UIImageView!
      
    override func viewDidLoad() {
        
        super.viewDidLoad()
    
        scrollView.minimumZoomScale = 1.0
        scrollView.maximumZoomScale = 6.0        
        // scrollView.delegate = self - it is set on the storyboard.
    }  
        
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
       
        return imgPhoto
    }

Solution 2 - Swift

I decided to add the imageView to a UIScrollView. It allows the user to zoom and pan over. Here is the code I used.

in order to set max/min zoom I used :

    scrollImg.minimumZoomScale = 1.0
    scrollImg.maximumZoomScale = 10.0

here is the rest of the code.

    var vWidth = self.view.frame.width
    var vHeight = self.view.frame.height

    var scrollImg: UIScrollView = UIScrollView()
    scrollImg.delegate = self
    scrollImg.frame = CGRectMake(0, 0, vWidth!, vHeight!)
    scrollImg.backgroundColor = UIColor(red: 90, green: 90, blue: 90, alpha: 0.90)
    scrollImg.alwaysBounceVertical = false
    scrollImg.alwaysBounceHorizontal = false
    scrollImg.showsVerticalScrollIndicator = true
    scrollImg.flashScrollIndicators()
    
    scrollImg.minimumZoomScale = 1.0
    scrollImg.maximumZoomScale = 10.0

    defaultView!.addSubview(scrollImg)
    
    imageView!.layer.cornerRadius = 11.0
    imageView!.clipsToBounds = false
    scrollImg.addSubview(imageView!)

I also had to add this as well

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

Swift 3 & above function prototype

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

Solution 3 - Swift

Supporting Swift 5.1, You can create an extension of UIImageView, like this:

extension UIImageView {
  func enableZoom() {
    let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(startZooming(_:)))
    isUserInteractionEnabled = true
    addGestureRecognizer(pinchGesture)
  }

  @objc
  private func startZooming(_ sender: UIPinchGestureRecognizer) {
    let scaleResult = sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)
    guard let scale = scaleResult, scale.a > 1, scale.d > 1 else { return }
    sender.view?.transform = scale
    sender.scale = 1
  }
}

Solution 4 - Swift

The option for swift 4

class ViewController: UIViewController, UIScrollViewDelegate {

@IBOutlet weak var scrolView: UIScrollView!
@IBOutlet weak var imgPhoto: UIImageView!

  override func viewDidLoad() {
    super.viewDidLoad()
    scrolView.delegate = self
    scrolView.minimumZoomScale = 1.0
    scrolView.maximumZoomScale = 10.0
  }

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

Solution 5 - Swift

You can use ImageScrollView open source, a zoomable and scrollable image view. http://github.com/huynguyencong/ImageScrollView

Like this opensource, add ImageView to ScrollView

open class ImageScrollView: UIScrollView {
   var zoomView: UIImageView? = nil
}

extension ImageScrollView: UIScrollViewDelegate{
    
    public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return zoomView
    }
    
    public func scrollViewDidZoom(_ scrollView: UIScrollView) {
        adjustFrameToCenter()
    }
}

Solution 6 - Swift

Using Swift 5.0, here is how it works for me:

let myImageView = UIImageView(image: myImage)
myImageView.isUserInteractionEnabled = true
let pinchMethod = UIPinchGestureRecognizer(target: self, action: #selector(pinchImage(sender:)))
myImageView.addGestureRecognizer(pinchMethod)

@objc func pinchImage(sender: UIPinchGestureRecognizer) {
  guard let sender.view != nil else { return }

if let scale = (sender.view?.transform.scaledBy(x: sender.scale, y: sender.scale)) {
  guard scale.a > 1.0 else { return }
  guard scale.d > 1.0 else { return }
  sender.view?.transform = scale
  sender.scale = 1.0
 }
}

You can use scale.a, scale.b, scale.c, scale.d, scale.tx and scale.ty to set your scale limits.

Solution 7 - Swift

In my view, the problem is your determination of currentScale. It always equals 1, because you change the scale of your imageView. You should assign your currentScale as follows:

let currentScale = self.imageView?.frame.size.width / self.imageView?.bounds.size.width  

Solution 8 - Swift

Swift 3 solution

By default UIImageView's userInteration is disabled. Enable it before adding any gestures in UIImageView.

imgView.isUserInteractionEnabled = true

> The scale factor relative to the points of the two touches in screen > coordinates

var lastScale:CGFloat!
func zoom(gesture:UIPinchGestureRecognizer) {
    if(gesture.state == .began) {
        // Reset the last scale, necessary if there are multiple objects with different scales
        lastScale = gesture.scale
    }
    if (gesture.state == .began || gesture.state == .changed) {
    let currentScale = gesture.view!.layer.value(forKeyPath:"transform.scale")! as! CGFloat
    // Constants to adjust the max/min values of zoom
    let kMaxScale:CGFloat = 2.0
    let kMinScale:CGFloat = 1.0
    var newScale = 1 -  (lastScale - gesture.scale)
    newScale = min(newScale, kMaxScale / currentScale)
    newScale = max(newScale, kMinScale / currentScale)
    let transform = (gesture.view?.transform)!.scaledBy(x: newScale, y: newScale);
    gesture.view?.transform = transform
    lastScale = gesture.scale  // Store the previous scale factor for the next pinch gesture call
  }
}

Solution 9 - Swift

Swift 3 solution

This is the code I used. I added imageView to scrollView as a subview.

class ZoomViewController: UIViewController,UIScrollViewDelegate {

@IBOutlet weak var scrollView:UIScrollView!
@IBOutlet weak var imageView:UIImageView!

override func viewDidLoad() {

        super.viewDidLoad()
        scrollView.delegate = self

        scrollView.minimumZoomScale = 1.0
        scrollView.maximumZoomScale = 10.0//maximum zoom scale you want
        scrollView.zoomScale = 1.0

}

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

Solution 10 - Swift

I posted an answer here for zoom functionality with both pinch and double tap in Swift 3. Works perfectly.

Solution 11 - Swift

I think the biggest problem is at the end of your func, you have sender.scale = 1. If you remove that line of code, your image shouldn't just bounce back each time.

Solution 12 - Swift

This is an old question but I don't see any answers that explain what is wrong with the original code.

This line:

let currentScale = self.view.frame.size.width / self.view.bounds.size.width

Is working on the main view rather than the imageView so the scale calculation is always ~1

This simple change makes it behave as expected

let currentScale = sender.view!.frame.size.width / sender.view!.bounds.size.width

by changing self to sender (and forcing view to unwrap) the scale calculation works as expected.

Solution 13 - Swift

I ended up here, probably searching the wrong way.

I was after having my imageView in contentMode = .centre. But I was judging it too zoomed in and I was searching a way to zoom it out. Here's how:

    self.imageView.contentScaleFactor = 3

1 is as if you were doing anything. More that 1 zooms out... 3 works for me but you need to test it out.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRandomBytesView Question on Stackoverflow
Solution 1 - SwiftParth Changela View Answer on Stackoverflow
Solution 2 - SwiftRandomBytesView Answer on Stackoverflow
Solution 3 - SwiftJohn LimaView Answer on Stackoverflow
Solution 4 - SwiftHeretic SicView Answer on Stackoverflow
Solution 5 - SwifthuyncView Answer on Stackoverflow
Solution 6 - SwiftGabriel SóriaView Answer on Stackoverflow
Solution 7 - SwiftAndreyView Answer on Stackoverflow
Solution 8 - SwiftRajeshKumar RView Answer on Stackoverflow
Solution 9 - SwiftTharangaView Answer on Stackoverflow
Solution 10 - SwiftAkhilendra SinghView Answer on Stackoverflow
Solution 11 - SwiftLoganView Answer on Stackoverflow
Solution 12 - SwiftDean WardView Answer on Stackoverflow
Solution 13 - SwiftiOS FlowView Answer on Stackoverflow