views:

357

answers:

1

I'm looking to use Core Animation to simulate a flip clock animation in a Mac application. Currently I have three CALayer's representing the top and bottom half of the digit, and a third used to represent the flip animation (a solution found in the follow article: Creating an iPad flip-clock with Core Animation.

The animation of the flip layer is broken into two stages: flipping from the top to the middle of the digit, and then from the middle to the bottom. To achieve this, I use a delegate function which is called whenever an animation ends:

- (void)animationDidStop:(CAAnimation *)oldAnimation finished:(BOOL)flag
{
    int digitIndex = [[oldAnimation valueForKey:@"digit"] intValue];    
    int currentValue = [[oldAnimation valueForKey:@"value"] intValue];

    NSMutableArray *digit = [digits objectAtIndex:digitIndex];
    CALayer *flipLayer = [digit objectAtIndex:tickerFlip];
    CALayer *bottomLayer = [digit objectAtIndex:tickerBottom];

    if([[oldAnimation valueForKey:@"state"] isEqual:@"top"] && flag) {
        NSLog(@"Top animation finished");

        [CATransaction begin];
        [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
        flipLayer.contents = [bottomImages objectAtIndex:currentValue];
        flipLayer.anchorPoint = CGPointMake(0.0, 1.0);
        flipLayer.hidden = NO;
        [CATransaction commit];

        CABasicAnimation *anim = [self generateAnimationForState:@"bottom"];
        [anim setValue:[NSString stringWithFormat:@"%d", digitIndex] forKey:@"digit"];
        [anim setValue:[NSString stringWithFormat:@"%d", currentValue] forKey:@"value"];
        [flipLayer addAnimation:anim forKey:nil];
    } else if([[oldAnimation valueForKey:@"state"] isEqual:@"bottom"] && flag) {
        NSLog(@"Bottom animation finished");

        // Hide our flip layer
        [CATransaction begin];
        [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
        bottomLayer.contents = [bottomImages objectAtIndex:currentValue];
        flipLayer.hidden = YES;
        flipLayer.anchorPoint = CGPointMake(0.0, 0.0);
        [CATransaction commit];
    }
}

This delegate function makes use of a helper function which generates the transform for the flip layer depending upon its state:

- (CABasicAnimation *)generateAnimationForState:(NSString *)state
{
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
    anim.duration = 0.15;
    anim.repeatCount = 1;

    // Check which animation we're doing
    if([state isEqualToString:@"top"]) 
    {
        anim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 1, 0, 0)];
        anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI/2, 1, 0, 0)];
    } 
    else 
    {
        anim.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-M_PI/2, 1, 0, 0)];
        anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 1, 0, 0)];
    }

    anim.delegate = self;
    anim.removedOnCompletion = NO;

    // Set our animations state
    [anim setValue:state forKey:@"state"];

    return anim;
}

This solution works but causes some slight flickering when an animation is in progress. I believe this is due to the transform on my flip layer resetting between the 'top' and 'bottom' animations. It's important to note that after the first stage of the animation completes, I set the flip layers anchor point to the top of the image, ensuring the flip pivots correctly.

Currently I'm unsure if my animation has been setup optimally. I'm new to transformations and Core Animation in general. Can anyone point me in the right direction?

A: 

After

anim.removedOnCompletion = NO; 

try inserting this code:

anim.fillMode = kCAFillModeForwards;

And let me know. Essentially the code snippet is supposed to prevent the 'reset' that is causing the flicker.

dytrivedi