Limiting UIPinchGestureRecognizer Zoom Levels

Here is how to use a UIPinchGestureRecognizer and how to limit it's zoom levels on your custom views and content. My use case was for resizing images on a custom view. I wanted to prevent very large images and to prevent very small images. Very large images have a ton of pixilation and artifacts. While very small images are hard to touch and a user cannot do anything useful with them.

Basic Math

1. We know: currentSize * scaleFactor = newSize

2. Clamp the maximum scale factor using the proportion maxScale / currentScale

3. Clamp the minimum scale factor using the proportion minScale / currentScale

The code below assumes there is an instance variable CGFloat lastScale and that a view has been set for the UIPinchGestureRecognizer.

Sample Code

#import <QuartzCore/QuartzCore.h>   // required for working with the view's layers

//....

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer {

if([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [gestureRecognizer scale];
}

if ([gestureRecognizer state] == UIGestureRecognizerStateBegan ||
[gestureRecognizer state] == UIGestureRecognizerStateChanged) {

CGFloat currentScale = [[[gestureRecognizer view].layer valueForKeyPath:@"transform.scale"] floatValue];

// Constants to adjust the max/min values of zoom
const CGFloat kMaxScale = 2.0;
const CGFloat kMinScale = 1.0;

CGFloat newScale = 1 -  (lastScale - [gestureRecognizer scale]); // new scale is in the range (0-1)
newScale = MIN(newScale, kMaxScale / currentScale);
newScale = MAX(newScale, kMinScale / currentScale);
CGAffineTransform transform = CGAffineTransformScale([[gestureRecognizer view] transform], newScale, newScale);
[gestureRecognizer view].transform = transform;

lastScale = [gestureRecognizer scale];  // Store the previous scale factor for the next pinch gesture call
}
}