In this episode I cover Facebook's new, shiny animation framework called Pop. With it we explore spring & decay animations that can make your apps feel more alive.
Episode Links Source Code Pop on Github Introducing Pop Facebook Paper for iOS Moving a View with a Spring Animation - (IBAction)tapView:(UITapGestureRecognizer *)recognizer { CGPoint location = [recognizer locationInView:self.view]; POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition]; anim.toValue = [NSValue valueWithCGPoint:location]; anim.springBounciness = 20; anim.springSpeed = 1; [self.imageView.layer pop_addAnimation:anim forKey:@"move"]; } Animating Scale with a Spring Animation - (IBAction)tap:(UITapGestureRecognizer *)recognizer { const CGFloat LargeSize = 256.0f; const CGFloat SmallSize = 64.0f; POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds]; if (self.imageView.frame.size.width >= LargeSize) { anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, SmallSize, SmallSize)]; } else { anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, LargeSize, LargeSize)]; } anim.springSpeed = 10; anim.springBounciness = 10; [self.imageView.layer pop_addAnimation:anim forKey:@"scale"]; } Drag and Slide with Decay Animations - (IBAction)pan:(UIPanGestureRecognizer *)recognizer { [self.imageView.layer pop_removeAnimationForKey:@"move"]; [self.imageView.layer pop_removeAnimationForKey:@"slide"]; switch (recognizer.state) { case UIGestureRecognizerStateBegan: case UIGestureRecognizerStateChanged: { CGPoint translation = [recognizer translationInView:self.view]; CGPoint center = self.imageView.center; center.x += translation.x; center.y += translation.y; self.imageView.center = center; [recognizer setTranslation:CGPointZero inView:self.view]; break; } case UIGestureRecognizerStateEnded: { POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPosition]; anim.deceleration = 0.998; anim.velocity = [NSValue valueWithCGPoint:[recognizer velocityInView:self.view]]; [self.imageView.layer pop_addAnimation:anim forKey:@"slide"]; break; } case UIGestureRecognizerStateCancelled: break; default: break; } } Notice how we cancel the animations when dragging, so we don't conflict with other animations that may be running at the same time. Animating Color and Bounds Change of a UIButton In this example, we have a button that changes state, that might be used as a confirmation button. - (void)tap:(UITapGestureRecognizer *)recognizer { _isToggled = !_isToggled; UIColor *targetColor; CGRect targetBounds; CGFloat targetRadius; if (_isToggled) { targetColor = [UIColor greenColor]; targetBounds = CGRectMake(initialBounds.origin.x - 0.5 * initialBounds.size.width, initialBounds.origin.y + 0.25 * initialBounds.size.height, initialBounds.size.width * 2, initialBounds.size.height * .5); targetRadius = 10.0f; } else { targetColor = [UIColor blueColor]; targetBounds = initialBounds; targetRadius = 36.0f; } // TODO animate POPSpringAnimation *colorAnim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBackgroundColor]; colorAnim.toValue = (id)[targetColor CGColor]; colorAnim.springSpeed = 6; [self.layer pop_addAnimation:colorAnim forKey:@"color"]; POPSpringAnimation *boundsAnim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds]; boundsAnim.toValue = [NSValue valueWithCGRect:targetBounds]; boundsAnim.springSpeed = 6; [self.layer pop_addAnimation:boundsAnim forKey:@"bounds"]; POPSpringAnimation *cornerAnim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerCornerRadius]; cornerAnim.toValue = @(targetRadius); cornerAnim.springSpeed = 6; [self.layer pop_addAnimation:cornerAnim forKey:@"corner"]; }