Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale UIView with the top center as the anchor point?

I'm scaling a UIView with CGAffineTransformMakeScale but I want to keep it anchored to it's current top center point as it's scaled.

I've looked into setting view.layer.anchorPoint but I believe I need to use this in conjunction with setting view.layer.position to account for the change in the anchor point.

If anyone could point me in the right direction I'd be very grateful!

like image 397
Alistair Holt Avatar asked Dec 23 '12 01:12

Alistair Holt


2 Answers

Take a look at my answer here to understand why your view is moving when you change the anchor point: https://stackoverflow.com/a/12208587/77567

So, start with your view's transform set to identity. When the view is untransformed, find the center of its top edge:

CGRect frame = view.frame;
CGPoint topCenter = CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame));

Then the anchor point to the middle of the top edge:

view.layer.anchorPoint = CGPointMake(0.5, 0);

Now the layer's position (or the view's center) is the position of the center of the layer's top edge. If you stop here, the layer will move so that the center of its top edge is where its true center was before changing the anchor point. So change the layer's position to the center of its top edge from a moment ago:

view.layer.position = topCenter;

Now the layer stays in the same place on screen, but its anchor point is the center of its top edge, so scales and rotations will leave that point fixed.

like image 179
rob mayoff Avatar answered Oct 19 '22 02:10

rob mayoff


By using an extension

Scaling an UIView with a specific anchor point while avoiding misplacement:

extension UIView {
    func applyTransform(withScale scale: CGFloat, anchorPoint: CGPoint) {
        layer.anchorPoint = anchorPoint
        let scale = scale != 0 ? scale : CGFloat.leastNonzeroMagnitude
        let xPadding = 1/scale * (anchorPoint.x - 0.5)*bounds.width
        let yPadding = 1/scale * (anchorPoint.y - 0.5)*bounds.height
        transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: xPadding, y: yPadding)
    }
}

So to shrink a view to half of its size with its top center as anchor point:

view.applyTransform(withScale: 0.5, anchorPoint: CGPoint(x: 0.5, y: 0))
like image 24
Lausbert Avatar answered Oct 19 '22 02:10

Lausbert