A simple keyframe-based animation framework for UIKit. Perfect for scrolling app intros.
Objective-C C# F# Other
Switch branches/tags
Clone or download
#1 Compare This branch is 27 commits ahead, 130 commits behind IFTTT:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Jazz Hands

Build Status

Jazz Hands is a simple keyframe-based animation framework for UIKit. Animations can be controlled via gestures, scroll views, KVO, or ReactiveCocoa.

Jazz Hands is used extensively in IFTTT for iPhone and iPad, most famously in the app intro:


##Demo App

Check out the demo app to see a simple demonstration of moving, resizing, fading, and hiding views in a scrolling app intro.

cd JazzHandsDemo
pod install
open JazzHandsDemo.xcworkspace


It's recommended that you install from CocoaPods, but you may alternatively just copy the contents of /src into your project.

##Quick Start

First, add JazzHands to your UIViewController. If you created your UIViewController with a XIB or Storyboard, make sure Autolayout is off for this file.

import "IFTTTJazzHands.h"

Now, create an Animator to manage all of the animations in this UIViewController.

@property (nonatomic, strong) IFTTTAnimator *animator;

// later...

self.animator = [IFTTTAnimator new];

Create an animation for a view that you want to animate. There are multiple types of animation that can be applied to a view. For this example, we'll use IFTTTFrameAnimation, which moves and sizes a view.

IFTTTFrameAnimation *frameAnimation = [IFTTTFrameAnimation new];
frameAnimation.view = viewThatYouWantToAnimate;

Register the animation with the animator.

[self.animator addAnimation:frameAnimation];

Add some keyframes to the animation. Let's move this view 140 points left, and double the size, between times 30 and 60.

[frameAnimation addKeyFrame:[[IFTTTAnimationKeyFrame alloc] initWithTime:30 andFrame:CGRectMake(10, 10, 100, 100)]];
[frameAnimation addKeyFrame:[[IFTTTAnimationKeyFrame alloc] initWithTime:60 andFrame:CGRectMake(150, 10, 200, 200)]];

Now, to animate the view, tell the animator what time it is. For example, to tie this animation to a UIScrollView, notify the animator of time in the scroller's delegate method.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
  [super scrollViewDidScroll:scrollView];
  [self.animator animate:scrollView.contentOffset.x];

This will produce an effect where the view will be at 10,10 and sized 100x100 for scroll positions 0 to 30. Between scroll positions 30 and 60, the view will grow and move until scroll position 61, where it will be locked to 150, 10 and 200x200.

##Animation Types

Jazz Hands supports several types of animations:

  • IFTTTFrameAnimation moves and sizes views.
  • IFTTTAlphaAnimation creates fade effects.
  • IFTTTHideAnimation hides and shows views.
  • IFTTTAngleAnimation for rotation effects.
  • IFTTTTransform3DAnimation for 3D transforms.
  • IFTTTScaleAnimation to scale view sizes.
  • IFTTTConstraintsAnimation animates AutoLayout constraint constants.

##More Examples


Say you want to perform some animations based on a UITableView's scroll offset, but you don't want to be the delegate for that table? ReactiveCocoa is perfect for that.

[RACObserve(self.tableView, contentOffset) subscribeNext:^(NSValue *value) {
  NSInteger y = floor(self.tableView.contentOffset.y);
  [self.animator animate:y];


Or, maybe you want to animate some views based upon the position of another view? Jazz Hands works well with KVO.

- (void)viewDidLoad
  [self.viewToMirror addObserver:self

- (void)observeValueForKeyPath:(NSString *)keyPath
                        change:(NSDictionary *)change
                       context:(void *)context {

  if ([keyPath isEqualToString:@"frame"]) {
    [self.animator animate:CGRectGetMinY(self.viewToMirror.frame)];
  } else {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];


Jazz Hands is flexible enough that it can accept timer input from many different types of sources, including UIGestureRecognizer.

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
  [self.animator animate:[recognizer locationOfTouch:0 inView:self.view]];


An animator can only handle one animation per type per view. If you want multiple animations of the same type on a view, use keyframes.

Copyright 2014 IFTTT Inc