objective-cmacoscocoansanimationnsanimationcontext

Rotating NSView around center


I'm trying to animate the rotation of an NSView around its center, but it keeps shifting side to side during rotation. What is causing this?

-(void)startRefreshAnimation {

    [NSAnimationContext beginGrouping];
    [[NSAnimationContext currentContext] setDuration:1.0];
    [[NSAnimationContext currentContext] setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    [NSAnimationContext currentContext].completionHandler = ^{ [self startRefreshAnimation]; };
    [[view animator] setFrameCenterRotation:previousRotation - 90.0];
    previousRotation += -90.0;
    [NSAnimationContext endGrouping];

}

Shift up during rotation:

enter image description here

Shift down during rotation:

enter image description here


Solution

  • From the documentation:

    If the application has altered the layer’s anchorPoint property, the behavior is undefined. Sending this message to a view that is not managing a Core Animation layer causes an exception.

    https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/Reference/NSView.html

    Is your view managing a CALayer with an unmodified anchor point?

    EDIT

    I setup similar code at got the exact same results. No adjust of origin or anchor point could resolve this problem. My theory is that this particular method contains bugs (does for autolayout), or works in a way which we don't anticipate. I achieved the correct effect using CABasicAnimation.

    /* setup */
    
    ....
         _view.layer.anchorPoint = CGPointMake(0.5f, 0.5f);
         _view.layer.position = ...
    
        [self startRefreshAnimation];
    }
    
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
    {
        [self startRefreshAnimation];
    }
    
    -(void)startRefreshAnimation {
    
        CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        anim2.fromValue = [NSNumber numberWithFloat:previousRotation * (M_PI / 180.0f)];
        anim2.toValue = [NSNumber numberWithFloat:(previousRotation + 90.0f) * (M_PI / 180.0f)];
        previousRotation = previousRotation + 90.0f;
        anim2.duration = 1.0f;
        anim2.delegate = self;
        [_view.layer addAnimation:anim forKey:@"transform"];
    }