2

Problem: I have a pinch gesture recognizer on a View Controller which I'm using to scale an image nested inside the View Controller. The transform below works fine, except that the image is scaled from the upper left instead of the center. I want it to scale from the center.

Setup:

  • a UIImageView set to Aspect Fill mode (nested within a few views, origin set to center).
  • a UIPinchGestureRecognizer on the container View Controller

I verified:

  • anchorPoint for image view is (0.5, 0.5)
  • the center is moving after every transform
  • no auto layout constraints on the view or its parent (at least at build time)

Also, I tried setting center of the UIImageView after the transform, the change doesn't take effect until after the user is done pinching.

I don't want to center the image on the touch because the image is smaller than the view controller.

CGFloat _lastScale = 1.0;
- (IBAction)pinch:(UIPinchGestureRecognizer *)sender {
    if ([sender state] == UIGestureRecognizerStateBegan) {
        _lastScale = 1.0;
    }

    CGFloat scale = 1.0 - (_lastScale - [sender scale]);
    _lastScale = [sender scale];
    CGAffineTransform currentTransform = self.imageView.transform;
    CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
    [self.imageView setTransform:newTransform];
    NSLog(@"center: %@", NSStringFromCGPoint(self.imageView.center));
}

Here's a complete project demonstrating the issue. https://github.com/adamloving/PinchDemo

Adam Loving
  • 443
  • 5
  • 12

1 Answers1

2

no auto layout constraints on the view or its parent (at least at build time)

If your nib / storyboard uses auto layout, then there are certainly auto layout constraints, even if you did not deliberately construct them. And let's face it, auto layout does not play nicely with view transforms. A scale transform should scale from the center, but auto layout is fighting against you, forcing the frame to be reset by its top and its left (because that is where the constraints are).

See my essay on this topic here:

How do I adjust the anchor point of a CALayer, when Auto Layout is being used?

See also the discussion of this problem in my book.

In your case, the simplest solution is probably to apply the transform to the view's layer rather than to the view itself. In other words, instead of saying this sort of thing:

self.v.transform = CGAffineTransformMakeScale(1.3, 1.3);

Say this sort of thing:

self.v.layer.transform = CATransform3DMakeScale(1.3, 1.3, 1);
Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thank you! Here's what fixed it for me `CATransform3D newTransform = CATransform3DScale(self.imageView.layer.transform, scale, scale, 1); self.imageView.layer.transform = newTransform;` – Adam Loving Jan 07 '14 at 04:53
  • VERY nice solution. Well done guys! This was a royal pain in the arse when working with pan gestures and AutoLayout. – brandonscript May 14 '14 at 17:50