Search code examples
iosuiscrollviewuipinchgesturerecognizercontentoffset

Horizontal-only pinch zoom in a UIScrollView


I'm using a UIPinchGestureRecognizer to adjust the width (not the height) of a view in a UIScrollView. It works with the pinch gesture's scale property, but the contentOffset of the scrollview doesn't change, so the view always increases on the right. This looks a bit better if I scale the contentOffset along with the width, since then the view increases from the left-most side of the screen.

The problem is that the location of the pinch is ignored - so it always appears that a pinch is on the left side of the screen.

I need to somehow factor in the location of the pinch to the contentOffset adjustment, so that the offset can be adjusted to keep the content at the pinch point to be in the same place.

Note: I cannot use built-in UIScrollView pinch-zoom gesture as I only want the zoom to be one dimension, horizontal. Also, I cannot use transforms on the UIView as I need to use the UIScrollView.


Solution

  • I was pinch zooming a graph, so the pinch adjusts the width constraint on the graph view.

    Here is the pinch handler:

    - (void) doPinch:(UIPinchGestureRecognizer*)pinch;
    {        
        CGFloat width = self.graphWidthConstraint.constant;
        CGFloat idealWidth = 1500;
        CGFloat currentScale = width / idealWidth;
        CGFloat scale = currentScale - (1.0 - pinch.scale);
    
        CGFloat minScale = 0.5;
        CGFloat maxScale = 3.0;
        scale = MIN(scale, maxScale);
        scale = MAX(scale, minScale);
    
        CGPoint locationScrollview = [pinch locationInView:self.graphScrollView];
        CGFloat pinchXNormalized = locationScrollview.x / width;
    
        CGPoint locationView = [pinch locationInView:self.view];
    
        // resize
        CGFloat newWidth = idealWidth * scale;
        self.graphWidthConstraint.constant = newWidth;
    
        // set offset to position point under touch
        CGFloat pinchXScaled = newWidth * pinchXNormalized;
        CGFloat x = pinchXScaled - locationView.x;
        self.graphScrollView.contentOffset = CGPointMake(x, 0);
    
        pinch.scale = 1;
    }