How To Apply Complex CALayer Transform Changes?

500 views Asked by At

I need a complex continuous animation of a UIView that involves setting CATransform3D rotation and translation properties that need to be calculated, so a standard animation is no option.

I turned to using CALayer animation. And have this:

self.displayLink = [self.window.screen displayLinkWithTarget:self selector:@selector(update:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

- (void)update:(CADisplayLink*)sender
{
    CGFloat elapsedTime = sender.timestamp - self.lastTimestamp;
    self.lastTimestamp = sender.timestamp;

    self.rotation += elapsedTime * 0.1;  // Factor determines speed.

    // This is just example for SO post; the real animation is more complicated!
    CATransform3D transform;
    transform = CATransform3DMakeRotation(self.rotation, 1.0, 0.0, 0.0);
    self.imageLayer.transform = transform;
}

Here self.imageLayer is a CALayer whose contents has been set with an image and added as a sublayer to my base-view.

It does rotate 'a bit' but not continuously, sometimes it seems to stop or rotate backwards a bit.

It seems that assigning a new transform quite often does not have any effect because the self.rotation value is incremented much much more. Adding a [self setNeedsDisplay] did not help.

I've not done much with CALayers yet so I guess that I'm missing something very basic. Tried to find it for some time but all examples I found seem too far from what I want.

1

There are 1 answers

1
rob mayoff On BEST ANSWER

When you create your own layer and then modify its properties, it animates them implicitly (see “Animating Simple Changes to a Layer’s Properties”. You're not seeing the changes you expect because Core Animation is animating the changes rather than applying them instantly.

You need to disable implicit animation. There are several ways to disable it; see “Changing a Layer’s Default Behavior”. Or search stack overflow for “disable implicit animations”. Here's one way:

NSDictionary *actions = @{ @"transform": [NSNull null] };
self.imageLayer.actions = actions;

Just do that once, where you create imageLayer.