How would I be able to limit the scale of the UIPinchGestureRecognizer to a min and max level? The scale property below seems to be relative to the last known scale (the de
The problem with most of the other answers is that they are trying to deal with scale as a linear value, when in fact it is non-linear due to the way UIPinchGestureRecognizer calculates its scale property based on the touch distance. When this isn't taken into account, the user must use more or less pinch distance to 'undo' the scaling applied by a previous pinch gesture.
Consider: suppose transform.scale = 1.0 and I place my fingers 6cm apart on the screen, then pinch inwards to 3cm apart - the resulting gestureRecognizer.scale is 0.5, and 0.5-1.0 is -0.5, so transform.scale will become 1.0+(-0.5) = 0.5. Now, I lift my fingers, place them back down 3cm apart and pinch outwards to 6cm. The resulting gestureRecognizer.scale will be 2.0, and 2.0-1.0 is 1.0, so transform.scale will become 0.5+1.0 = 1.5. Not what I wanted to happen.
The fix is to calculate the delta pinch scale as a proportion of its previous value. I place my fingers down 6cm apart, and pinch inwards to 3cm, so gestureRecognizer.scale is 0.5. 0.5/1.0 is 0.5, so my new transform.scale is 1.0*0.5 = 0.5. Next, I place my fingers down 3cm apart, and pinch outwards to 6cm. gestureRecognizer.scale is then 2.0, and 2.0/1.0 is 2.0, so my new transform.scale is 0.5*2.0 = 1.0, which is exactly what I wanted to happen.
Here it is in code:
in -(void)viewDidLoad:
self.zoomGestureCurrentZoom = 1.0f;
in -(void)onZoomGesture:(UIPinchGestureRecognizer*)gestureRecognizer:
if ( gestureRecognizer.state == UIGestureRecognizerStateBegan )
{
self.zoomGestureLastScale = gestureRecognizer.scale;
}
else if ( gestureRecognizer.state == UIGestureRecognizerStateChanged )
{
// we have to jump through some hoops to clamp the scale in a way that makes the UX intuitive
float scaleDeltaFactor = gestureRecognizer.scale/self.zoomGestureLastScale;
float currentZoom = self.zoomGestureCurrentZoom;
float newZoom = currentZoom * scaleDeltaFactor;
// clamp
float kMaxZoom = 4.0f;
float kMinZoom = 0.5f;
newZoom = MAX(kMinZoom,MIN(newZoom,kMaxZoom));
self.view.transform = CGAffineTransformScale([[gestureRecognizer view] transform], newZoom, newZoom);
// store for next time
self.zoomGestureCurrentZoom = newZoom;
self.zoomGestureLastScale = gestureRecognizer.scale;
}