Search code examples
objective-cioscore-animationcatransform3d

Smooth Animation on CAKeyframeAnimation for CATransform3D animations


I've created my own transition animation between views. I animate two properties, the position and the transform, to provide a cube-like transition between views. The frame uses CABasicAnimation while the transform uses a "2-stage" CAKeyframeAnimation. Everything works fine except for one small detail I can't seem to figure out. In my transition I apply a CATransform3DScale on the middle key frame to create a zoom-in/zoom-out effect. That works fine except the animation looks slightly jerky. It's animating the between the key frames in a linear fashion, and I would like to smooth that out. Now CAKeyframeAnimation has a way to do that using calculationMode, but it doesn't seem to work for transforms. I've tried setting it to kCAAnimationCubic and kCAAnimationCubicPaced with no effect.

Here is the code that animates one view's transform (a similar block of code animates the other view):

    CAKeyframeAnimation *aTransform = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    CATransform3D transform1 = RotateOnX(toView, M_PI_4);
    transform1 = CATransform3DScale(transform1, RotationalZoom, RotationalZoom, RotationalZoom);
    [aTransform setValues:Array([NSValue valueWithCATransform3D:RotateOnX(toView, M_PI_2)],
                                [NSValue valueWithCATransform3D:transform1],
                                [NSValue valueWithCATransform3D:RotateOnX(toView, 0)])];
    [toView.layer addAnimation:aTransform forKey:@"transform"];

Note: RotateOnX(UIView *, CGFloat) is a block that returns a transform for a view rotated on X by the desired Radians.

As you can see I only set a scaling transform on the middle key frame. Also, the rotation of the view is perfectly smooth, it's only the scaling that appears to 'jerk' as it changes direction.

Does anyone have any ideas on how to smooth out the scaling/zooming?


Solution

  • Try the timingFunctions property. Since you have 3 keyframes, you need 2 timing functions: one for the animation from keyframe 0 to keyframe 1, and another for the animation from keyframe 1 to keyframe 2.

    aTransform.timingFunctions = [NSArray arrayWithObjects:
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInOut],
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInOut],
        nil];