8

I am using the code below to rotate UIImageViews to different angles.

self.imageOne.transform = CGAffineTransformMakeRotation(CGFloat(-rotation))
self.imageTwo.transform = CGAffineTransformMakeRotation(CGFloat(-rotation-0.1))
self.imageThree.transform = CGAffineTransformMakeRotation(CGFloat(-change+0.1))

Is there any way to make it so the images pivot from the top instead of the middle? I would like to avoid getting sprites involved because I have never used them, and don't know how to make sprites work in a single view application. Thanks for your time.

2 Answers 2

25

What you are looking for is the anchorPoint property of your views' layers. This property basically represents the handle that is be used while the view is being moved around.

It defaults to the center of your view so and that why you are always seeing your view rotating form the middle.

You can use this great method i've found here on SO to change the anchorPoint of you views to the top (use CGPointMake(0, 0.5f))

// Swift version
// Place this before you set the transform property
setAnchorPoint(CGPointMake(0, 0.5), view: imageOne)
setAnchorPoint(CGPointMake(0, 0.5), view: imageTwo)
setAnchorPoint(CGPointMake(0, 0.5), view: imageThree)

func setAnchorPoint(anchorPoint: CGPoint, view: UIView) {
    var newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y)
    var oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y)

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform)
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform)

    var position : CGPoint = view.layer.position

    position.x -= oldPoint.x
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    view.layer.position = position;
    view.layer.anchorPoint = anchorPoint;
}

This is the objective c version of the same code

// Obj-c version
// Place this before you set the transform property
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageOne];
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageTwo];
[self setAnchorPoint:CGPointMake(0, 0.5f) forView:imageThree];

-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
    CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x,
                                   view.bounds.size.height * anchorPoint.y);
    CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x,
                                   view.bounds.size.height * view.layer.anchorPoint.y);

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);

    CGPoint position = view.layer.position;

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    view.layer.position = position;
    view.layer.anchorPoint = anchorPoint;
}

I'd encourage you to try to understand yourself what this code is doing once you have seen what the anchorPoint property represents. (the method is by user: Anand K)

Sign up to request clarification or add additional context in comments.

4 Comments

Your code doesn't work, the images rotate the same way they had, have you tested it? @mttcrsp
Sure i've tested it. I've made a project for testing it. If you want you can download it here. Just run it on the simulator, i've placed a button that makes the different views rotate, if you press it a couple of times in a row you'll see how it works.
Thanks, figured it out, just needed to swap the x and y for the points ex: setAnchorPoint(CGPointMake(0.5, 0), view: imageOne). Thanks for your time!
If the view is using autolayout, before view.layer.position = position we need to add view.translatesAutoresizingMaskIntoConstraints = true
5

Here's a Swift 3 extension based off of mttcrp's answer. It took me a while to figure out that the CGPoint isn't a coordinate in the view, but rather a proportion. For example, if you rotated the view around the point CGPoint(x: 0.5, y: 1) it would rotate around the bottom center of the view. Hope this helps!

extension UIView{
    func setAnchorPoint(anchorPoint: CGPoint) {

        var newPoint = CGPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y)
        var oldPoint = CGPoint(x: self.bounds.size.width * self.layer.anchorPoint.x, y: self.bounds.size.height * self.layer.anchorPoint.y)

        newPoint = newPoint.applying(self.transform)
        oldPoint = oldPoint.applying(self.transform)

        var position : CGPoint = self.layer.position

        position.x -= oldPoint.x
        position.x += newPoint.x;

        position.y -= oldPoint.y;
        position.y += newPoint.y;

        self.layer.position = position;
        self.layer.anchorPoint = anchorPoint;
    }
}

and you would use it like this:

let view = UIView() //This could be anything that inherits from UIView
view.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 1))

4 Comments

Using this function offsets the entire view half of its dimension in the opposite direction of the new anchor point. (For CGPoint(x: 0, y: 1), the view is offset half its height up).
@Skwiggs You are right. Did you find a solution to make it work as intended?
add self.translatesAutoresizingMaskIntoConstraints = true before self.layer.position = position; works for me
hackingwithswift.com/example-code/calayer/… You should appreciate Paul Hudson

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.