10

I want to mimic "zooming in" on a view. The larger view will be added as a subview to the smaller view's superview, and the larger view should look as if it is zooming in from the smaller view. Given the rect of the smaller view fromRect and the final frame of the zoomed in larger view finalRect, what would be the proper transform?

enter image description here

I imagine the method signature would be like the following, with view being the superview. I wrote this up to help myself, but cannot figure it out yet.

-(CGAffineTransform) translatedAndScaledTransformUsingViewRect:(CGRect)viewRect fromRect:(CGRect)fromRect inView:(UIView*) view
{
//calculate the scaling based on the final frame of viewToBeStretched (viewRect) vs the "fromRect"
CGFloat scaleX = ?, scaleY = ?;
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleX, scaleY);

//use translation instead of modifying the view's center, since frame changes with transforms are no good
CGFloat translationX = ?, translationY =?;
CGAffineTransform translationTransform = CGAffineTransformMakeTranslation(translationX, translationY);

CGAffineTransform final = CGAffineTransformConcat(scaleTransform, translationTransform);

return final;
}
akaru
  • 6,299
  • 9
  • 63
  • 102
  • You know, for the scales, it's just a matter of dividing the final lengths of the rect you wish to size it up to by the current size of the view. The translations are a little harder. – CodaFi Jan 29 '13 at 23:58
  • @CodaFi right, I could do just the scaling but didn't want to pollute the example here. I could easily just set the center property to the center of the smaller view, but that doesn't work with transforms. – akaru Jan 30 '13 at 00:10
  • 1
    The piece of code that you posted here seems to be correct, so what exactly does not work? – MrTJ Feb 06 '13 at 08:23
  • Anyway, I suggest to add the larger view to your superview _pre-transformed_ so that it exactly covers the smaller view as soon as the user clicks on it. Then you reset the the transformation matrix to identity matrix with an animation so as a result it will pop out from the place of the small view. – MrTJ Feb 06 '13 at 08:26

3 Answers3

21

So actual implementation is very simple:

- (CGAffineTransform)translatedAndScaledTransformUsingViewRect:(CGRect)viewRect fromRect:(CGRect)fromRect {

    CGSize scales = CGSizeMake(viewRect.size.width/fromRect.size.width, viewRect.size.height/fromRect.size.height);
    CGPoint offset = CGPointMake(CGRectGetMidX(viewRect) - CGRectGetMidX(fromRect), CGRectGetMidY(viewRect) - CGRectGetMidY(fromRect));
    return CGAffineTransformMake(scales.width, 0, 0, scales.height, offset.x, offset.y);

}

You can see full example here: https://github.com/vGubriienko/TransformTest

(I still need update it to use identity as full image)

Skie
  • 1,942
  • 16
  • 27
2

If you're only dealing with images, you can take advantage of the UIImageView's contentMode property and set it to UIViewContentModeScaleAspectFill. Then you can just do a [UIView transitionWithView:] and set the frame of your UIImageView to your final CGRect (or your whole screen because it will fill correctly). It will do the zooming-in effect you're looking for.

The best way to do this is to create a copy of the UIImageView as a subview of your superview and place it right on top of the original UIImageView and perform the transformations from there.

I wrote some functions to extend it to a UITableViewController a while back which lets you zoom-in on any UIImageView with a fade to black and zoom transition and the final image is zoomable and can be dismissed.

https://github.com/PeterCen/iOS-Image-Presenter/

Peter Cen
  • 276
  • 2
  • 8
  • Nicely done, but I need to do this using transforms, as this will be a view controller transition--thus the vc must be smaller at first. Your example assumes the UIImageView will take care of its content. – akaru Jan 30 '13 at 01:52
1

Turns out the best solution was to create a transform manually using a matrix.

akaru
  • 6,299
  • 9
  • 63
  • 102