Search code examples
iphoneobjective-cioscocoa-touchcore-animation

Creating itunes store style "jump" animation


I am creating a bookmarking feature for my app, I'd like to show the user what happens in a way similar to itunes store, when you buy something it jumps to tabBar. I once watched some WWDC video that explained this, but can't remember how to do it. Any idea where I should start looking for?


Solution

  • You can take a snapshot of the view you want to animate, then create an image layer, then use Core Animation to animate that to the tab bar. Here's the code I use to do that:

    - (void)animateSnapshotOfView:(UIView *)view toTab:(UINavigationController *)navController
    {
        NSUInteger targetTabIndex = [self.tabBarController.viewControllers indexOfObject:navController];
        NSUInteger tabCount = [self.tabBarController.tabBar.items count];
        // AFAIK there's no API (as of iOS 4) to get the frame of a tab bar item, so guesstimate using the index and the tab bar frame.
        CGRect tabBarFrame = self.tabBarController.tabBar.frame;
        CGPoint targetPoint = CGPointMake((targetTabIndex + 0.5) * tabBarFrame.size.width / tabCount, CGRectGetMidY(tabBarFrame));
        targetPoint = [self.window convertPoint:targetPoint fromView:self.tabBarController.tabBar.superview];
    
        UIGraphicsBeginImageContext(view.frame.size);
        [view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        CGRect frame = [self.window convertRect:view.frame fromView:view.superview];
        CALayer *imageLayer = [CALayer layer];
        imageLayer.contents = (id)image.CGImage;
        imageLayer.opaque = NO;
        imageLayer.opacity = 0;
        imageLayer.frame = frame;
        [self.window.layer insertSublayer:imageLayer above:self.tabBarController.view.layer];
    
        CGMutablePathRef path = CGPathCreateMutable();
        CGPoint startPoint = imageLayer.position;
        CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
        CGPathAddCurveToPoint(path,NULL,
                              startPoint.x + 100, startPoint.y,
                              targetPoint.x, targetPoint.y - 100,
                              targetPoint.x, targetPoint.y);
        CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        positionAnimation.path = path;
        CGPathRelease(path);
    
        CABasicAnimation *sizeAnimation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
        sizeAnimation.fromValue = [NSValue valueWithCGSize:imageLayer.frame.size];
        sizeAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(50, 50)];
    
        CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
        opacityAnimation.fromValue = [NSNumber numberWithFloat:0.75];
        opacityAnimation.toValue = [NSNumber numberWithFloat:0];
    
        CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
        animationGroup.animations = [NSArray arrayWithObjects:positionAnimation, sizeAnimation, opacityAnimation, nil];
        animationGroup.duration = 1.0;
        animationGroup.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
        animationGroup.delegate = self;
        [animationGroup setValue:imageLayer forKey:@"animatedImageLayer"];
    
        [imageLayer addAnimation:animationGroup forKey:@"animateToTab"];
    }