13

I've spent a lot of time trying to find a way to use CGAffineScale to transform a view to a given point, including messing around with anchor points, moving the centre of a view before and after transforming and comprehensive Googling. I am aware this would be a lot simpler with a UIScrollview; but I know it's technically possible to do without one, and it's become a splinter in my mind.

This answer gets remarkably close to what I want to achieve, but the answer only gives details on how to zoom to a given corner (instead of a given point) by cleverly moving the centre to the corner opposite the one you want to zoom in to.

How can I modify mvds' code to scale a UIView to any given point in a UIView?

CGFloat s = 3;
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, s, s);
CGFloat h = self.view.frame.size.height;
CGFloat w = self.view.frame.size.width;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
    self.view.transform = tr;
    self.view.center = CGPointMake(w-w*s/2,h*s/2);
} completion:^(BOOL finished) {}];
Community
  • 1
  • 1
glenstorey
  • 5,134
  • 5
  • 39
  • 71

2 Answers2

6

There are 2 steps involved: First you scale up the view you want to zoom in to. Then you set the center of this blown up view such that the part you want to see ends up in the middle of the view.

You should draw this out on paper and the formulas will follow: (untested)

CGFloat s = 3;
CGPoint p = CGPointMake(100, 200);
CGAffineTransform tr = CGAffineTransformScale(self.view.transform, s, s);
CGFloat h = self.view.frame.size.height;
CGFloat w = self.view.frame.size.width;
[UIView animateWithDuration:2.5 delay:0 options:0 animations:^{
    self.view.transform = tr;
    CGFloat cx = w/2-s*(p.x-w/2);
    CGFloat cy = h/2-s*(p.y-h/2);
    self.view.center = CGPointMake(cx, cy); //was: (w*s/2,h-h*s/2);
} completion:^(BOOL finished) {}];
Dennis
  • 2,119
  • 20
  • 29
mvds
  • 45,755
  • 8
  • 102
  • 111
  • 2
    Thanks so much for your answer. I did try this but it still zooms into the incorrect point. I've tried drawing this on paper as well, but the logic eludes me. – glenstorey Sep 12 '13 at 17:47
4

I actually ran into this very same problem myself. To fix it, all I did was change the anchor point of the view I was scaling because CGAffineTransforms are performed on the view in relation to its anchor point, so depending on where the anchor point is, the transform will scale, translate, or rotate the view differently. Here's the basic idea:

CGPoint pointToScaleTo = CGPointMake(x, y); //Just enter the coordinates you 
                                            //want to scale your view towards

CGFloat viewWidth = self.view.bounds.size.width;
CGFloat viewHeight = self.view.bounds.size.height;

CGFloat scaleFactorX = ...;
CGFloat scaleFactorY = ...;

CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleFactorX, scaleFactorY);

[UIView animateWithDuration:2.5f delay:0.0f options:0 animations:^{

    //I divide the x and y coordinates by the view width and height
    //because the anchor point coordinates are normalized to the range
    //0.0-1.0.
    self.view.layer.anchorPoint = CGPointMake(pointToScaleTo.x/viewWidth, pointToScaleTo.y/viewHeight);

    //Now that the anchor point has been changed, apply the scale transform
    self.view.layer.transform = scaleTransform;

} completion:^(BOOL finished) {}];
pasawaya
  • 11,515
  • 7
  • 53
  • 92
  • 1
    Thanks for your answer. Because of iOS7 (I think) I changed the CGAffineTransform line to `CATransform3D scaleTransform3D = CATransform3DMakeScale(scaleFactorX, scaleFactorY, 1.0);` (view.layer.transform had to be CATransform3D). What happens now is the view jumps so that the `pointToScaleTo` is in the centre (which isn't ideal - ideally I'd want to zoom toward the point rather than jump to, then zoom in) and then rotates -90ΒΊ. I'm not sure where I'm getting the rotation from. Do you know how to get it to zoom to the point rather than jump and then zoom? – glenstorey Sep 19 '13 at 18:35
  • You can convert the affine transformation into a `CATransform3D` using `self.view.layer.transform = CATransform3DMakeAffineTransform(scaleTransform);`. – Dennis Sep 29 '14 at 14:28