Take the 2-minute tour ×

NB: This is for a Cocoa app on OS X, NOT iOS.

I have a layer-backed NSButton (subclass of NSView). What I want to do is rotate that button using Core Animation. I'm using the following code to do it:

CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
a.fromValue = [NSNumber numberWithFloat:0];
a.toValue = [NSNumber numberWithFloat:-M_PI*2];
[_refreshButton.layer setAnchorPoint:CGPointMake(0.5, 0.5)];
a.duration = 1.8; // seconds
a.repeatCount = HUGE_VAL;
[_refreshButton.layer addAnimation:a forKey:nil];

This works, EXCEPT that when it runs, the layer jumps down and to the left so that its center point is at the origin point of the NSView, which is the lower-left corner at (0,0). The layer then rotates about its center, but obviously the jumping-to-the-lower-left-corner is not acceptable.

So, after much reading, I found this line in the 10.8 API release notes:

On 10.8, AppKit will control the following properties on a CALayer 
(both when "layer-hosted" or "layer-backed"): geometryFlipped, bounds, 
frame (implied), position, anchorPoint, transform, shadow*, hidden, 
filters, and compositingFilter. Use the appropriate NSView cover methods 
to change these properties.

This means that AppKit is "ignoring" my call to -setAnchorPoint in the code above and, instead, is setting that anchor point to the NSView's origin (0,0).

My question is: how do I solve this? What is the "appropriate NSView cover method" to set the anchorPoint for the layer (I can't find such a method on NSView). At the end of the day, I just want my button to rotate around its center point, indefinitely.

share|improve this question

1 Answer 1

up vote 9 down vote accepted

I don't see any methods on NSView that are a direct “cover” for anchorPoint.

What I do see in the 10.8 release notes, besides what you quoted, is this:

The anchorPoint is also always set to be (0,0), …

The anchorPoint controls which point of the layer is at position in the superlayer's coordinate system. NSView sets self.layer.anchorPoint to (0,0), which means the layer's lower-left corner is at self.layer.position.

When you set anchorPoint to (0.5,0.5), that means the center of the layer should be at the layer's position. Since you didn't modify position, this has the effect of moving the layer down and to the left, as you are seeing.

You need to compute the position you want the layer to have when its anchorPoint is (0.5,0.5), like this:

CGRect frame = _refreshButton.layer.frame;
CGPoint center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame));
_refreshButton.layer.position = center;
_refreshButton.layer.anchorPoint = CGPointMake(0.5, 0.5);
share|improve this answer
Perfect! You know; I saw the position property but didn't give it a try because I read the note above that says AppKit is going to control it. Thanks for the solution! –  Bryan Feb 13 '13 at 1:15
Any idea why the rotation M_PI/2 would rotate counter clockwise the first time and clockwise after that? –  greg Jul 8 at 4:23
I would have to see your code. You should post your own question. –  rob mayoff Jul 8 at 5:36
Here you go: stackoverflow.com/questions/24623725/… –  greg Jul 8 at 15:16

Your Answer


