Scaling a UIView with subviews staying the same size
Easiest way to scale a UIButton
or a UITableViewCell
is to set a transform on it:
view.transform = CGAffineTransformMakeScale(1.5f, 1.5f);
If this works for you that's perfect, but sometimes some subviews start looking bad when zoomed in, especially images and text.
To make the UIView
zoomed in, but the subviews the same size Linear Algebra comes in handy. Especially Invertable Matrices. We know that a matrix multiplied by its inverse matrix will result in an identity matrix.
In terms of UIView
transforms this means that if we multiply the scale transform by its inverse transform, the view will stay the same size. The UIViews
in iOS work in a way, that the resulting displayed view has the final transform as a product of all the transforms of its ancestors in the view hierarchy. So if the view
will have a scale transform set, and its subview
will have the inverse transform set, the subview
will visually stay the same size, while the view
will be scaled.
CGAffineTransform t = CGAffineTransformMakeScale(x,y);
CGAffineTransform it = CGAffineTransformInvert(t);
view.transform = t;
subview.transform = it;
Bonus question: How to make the scaled view look good?
After scaling the final view may not be pixel aligned with the device pixels. Especially if our scale parameter is not integral. This may result in blurry images and fonts.
For instance if a view
has a height of 257
and gets a scale parameter of 1.33
we get the final height of 341,81
which is not integral and the anti-aliasing kicks in.
To make sure our view.frame
stays integral after the transform, we have to use an approximate scale that is nearly the same as our original scale.
CGFloat sx = <something>;
CGFloat sy = <something else>;
CGFloat w = view.frame.size.width;
CGFloat h = view.frame.size.height;
CGFloat goodSx = ceilf(w * sx)/w;
CGFloat goodSy = ceilf(h * sx)/h;
CGAffineTransform t = CGAffineTransformMakeScale(goodSx, goodSy);
The above transform t
will make the view
look good scaled. This works because if we multiply the transform and the height, the result will be reduced to the output of the ceilf
function that is integral.
h * (ceilf(h * sx) / h) = ceilf(h * sx)