Question

I'm trying to chain two keyframe-based animations, but the second animation won't play for some reason. Any idea what's going on?

// Create an animation group to contain all album art animations
    CAAnimationGroup *albumArtAnimationGroup = [CAAnimationGroup animation];
    albumArtAnimationGroup.duration = 3.0;
    albumArtAnimationGroup.repeatCount = 0;

    // First album art translation animation
    CGMutablePathRef albumCoverPath = CGPathCreateMutable();
    CGPathMoveToPoint(albumCoverPath, NULL,
                      albumCover.layer.position.x,
                      albumCover.layer.position.y);
    CGPathAddLineToPoint(albumCoverPath, NULL,
                         albumCover.layer.position.x-[UIScreen mainScreen].bounds.size.height,
                         albumCover.layer.position.y);
    CAKeyframeAnimation *albumCoverTranslationAnimation;
    albumCoverTranslationAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    albumCoverTranslationAnimation.calculationMode = kCAAnimationLinear;
    albumCoverTranslationAnimation.path = albumCoverPath;
    albumCoverTranslationAnimation.duration = 1.0;

    // Second album art translation animation
    CGMutablePathRef albumCoverPath1 = CGPathCreateMutable();
    CGPathMoveToPoint(albumCoverPath1, NULL,
                      albumCover.layer.position.x+[UIScreen mainScreen].bounds.size.height,
                      albumCover.layer.position.y);
    CGPathAddLineToPoint(albumCoverPath1, NULL,
                         albumCover.layer.position.x,
                         albumCover.layer.position.y);
    CAKeyframeAnimation *albumCoverTranslationAnimation1;
    albumCoverTranslationAnimation1 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    albumCoverTranslationAnimation1.calculationMode = kCAAnimationLinear;
    albumCoverTranslationAnimation1.path = albumCoverPath1;
    albumCoverTranslationAnimation1.duration = 1.0;
    CFTimeInterval localAlbumLayerTime = [albumCover.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    albumCoverTranslationAnimation1.beginTime = localAlbumLayerTime + 1.0;

 albumArtAnimationGroup.animations = @[albumCoverTranslationAnimation, albumCoverTranslationAnimation1];

    [albumCover.layer addAnimation:albumArtAnimationGroup forKey:@"position"];

Edit

Solved. It turns out that either Apple's documentation was misleading, or I was using CACurrentMediaTime incorrectly. The code below did the trick.

albumArtAnimationGroup.duration = 2.0;
albumCoverTranslationAnimation.duration = 1.0;
albumCoverTranslationAnimation1.beginTime = 1;
albumArtAnimationGroup.animations = @[albumCoverTranslationAnimation, albumCoverTranslationAnimation1];
[albumCover.layer addAnimation:albumArtAnimationGroup forKey:@"position"];

However, according to Apple, I may possibly run into issues regarding the timing since I am not using CACurrentMediaTime(), as shown below.

To assist you in making sure time values are appropriate for a given layer, the CALayer class defines the convertTime:fromLayer: and convertTime:toLayer: methods. You can use these methods to convert a fixed time value to the local time of a layer or to convert time values from one layer to another. The methods take into account the media timing properties that might affect the local time of the layer and return a value that you can use with the other layer. Listing 5-3 shows an example that you should use regularly to get the current local time for a layer. The CACurrentMediaTime function is a convenience function that returns the computer’s current clock time, which the method takes and converts to the layer’s local time.

Listing 5-3 Getting a layer’s current local time

CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
Was it helpful?

Solution

When you add multiple animations to an animation group, the beginTime property starts at 0, and ends at the duration of the animation. So to chain a second animation, set it's beginTime to the duration of the first animation, and make the animation group's duration long enough for the entire animation sequence.

BTW, it might be simpler to create a single CAKeyframeAnimation that has the 2 paths combined together into one. It would be a lot less code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top