Skip to content

Instantly share code, notes, and snippets.

@fuji246
Last active November 9, 2019 00:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fuji246/c3d7a02ff6243185eb9e38d3f4d18220 to your computer and use it in GitHub Desktop.
Save fuji246/c3d7a02ff6243185eb9e38d3f4d18220 to your computer and use it in GitHub Desktop.
UIPinchGestureRecognizer Scale

I find the scale of UIPinchGestureRecognizer is confusing, so I did two experiments below, two ways to do the same thing.

Method 1

gestureRecognizer.scale start with 1.0 at the beginning of pinch (gestureRecognizer.state == .began), and gestureRecognizer.scale in later state (.changed or .end) is always based on that, for example, if the view size is view_size at the beginning of pinch (might not be the same with the original size orig_view_size), gestureRecognizer.scale always starts with 1.0, and if it becomes 2.0 later, it's size will be 2 * view_size, so the scale always based on that when the pinch starts. And we can get the scale at the beginning of pinch (gestureRecognizer.state == .began) lastScale = self.imageView.frame.width/self.imageView.bounds.size.width, so the scale of the original image now should be lastScale * gestureRecognizer.scale

  • lastScale: The scale of last round of Pinch, a round of Pinch is from state.start to state.end, and the scale is based on the original view size.

  • gestureRecognizer.scale: current scale, based on the view size after last round of Pinch.

  • currentScale: current scale, based on the orignial view size.

  • newScale: new scale, based on the orignial view size. newScale = lastScale * gestureRecognizer.scale, and you can limit the scale of the view by comparing the limitation with newScale.

    var lastScale:CGFloat = 1.0

    @objc func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
            var newScale = gestureRecognizer.scale
            if gestureRecognizer.state == .began {
                lastScale = self.imageView.frame.width/self.imageView.bounds.size.width
            }
            newScale = newScale * lastScale
            
            if newScale < minScale {
                newScale = minScale
            } else if newScale > maxScale {
                newScale = maxScale
            }

            let currentScale = self.imageView.frame.width/self.imageView.bounds.size.width
            self.imageView.transform = CGAffineTransform(scaleX: newScale, y: newScale)
            print("last Scale: \(lastScale), current scale: \(currentScale), new scale: \(newScale), gestureRecognizer.scale: \(gestureRecognizer.scale)")
    }

Method 2

gestureRecognizer.scale start with 1.0 on each Pinch notification, this require you reset gestureRecognizer.scale = 1 in the code in the end of each notification handler, so now gestureRecognizer.scale is based on the view size of last Pinch notification, NOT based on the view size at the beginning of pinch. This is the most important difference with method 1. And since we don't rely on the scale of last round, we don't need lastScale anymore.

  • currentScale: current scale, based on the orignial view size.

  • gestureRecognizer.scale: new scale, based on the view size of last Pinch (not the last round), the scale value based on the orignial view size will be currentScale * gestureRecognizer.scale

And we use transform.scaledBy now, which use the scale based on view size of last Pinch (not the last round).

    @objc func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
            let currentScale = self.imageView.frame.width/self.imageView.bounds.size.width
            var newScale = gestureRecognizer.scale
            if currentScale * gestureRecognizer.scale < minScale {
                newScale = minScale / currentScale
            } else if currentScale * gestureRecognizer.scale > maxScale {
                newScale = maxScale / currentScale
            }
            self.imageView.transform = self.imageView.transform.scaledBy(x: newScale, y: newScale)
            print("current scale: \(currentScale), new scale: \(newScale)")
            
            gestureRecognizer.scale = 1
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment