Overview
The Facebook’s open source animation framework named Pop was first released in late April 2014, that powers the animations in the Paper for iOS app. Pop Framework becomes easy to use if you have worked on Apple’s Core Animation before. Even if you have not, writing a basic animation using Pop is very easy.
Once you spend time on iOS animation, You will face lots of crazy things and too many LOCs to perform even a small task, but here Facebook’s pop animation framework will help you to overcome that.
Pop is an extensible animation engine for both iOS and OS X. It supports basic, spring, decay and custom animations.
There are a couple of things to adore about this library:
- It’s easy to use and fun
- It plays well with auto layout by allowing you to interact at the layer level
- You can animate constraints when needed
- It supports spring and dynamic animations
I’m expecting that you know about making new XCode project, so I’m skipping that part.
Installing CocoaPods
Install CocoaPods on System.CocoaPods Guides.
OR
If you have already added CocoaPods to your project then you’ll just need to add the following line to your Podfile:
pod 'pop'
Basic Animation
Basic animations make linear, ease-in, ease-out, and ease-in-ease-out animations simple to leverage.
In given example, I’m simply rotating the view. POPBasicAnimation class is used for Basic Animation. POPBasicAnimation has several different properties, but I have used toValue, fromValue, duration to define the behavior of the view.
Steps:
- Import framework in your UIViewController class: import pop
- Create the outlet variables for UIView.
@IBOutlet weak var animView: UIView!
- Create POPBasicAnimation object with using Layer Properties.
let anim = POPBasicAnimation(propertyNamed: kPOPLayerRotation)
- Set the toValue, fromValue, duration of the animation.
anim?.fromValue = 0 anim?.toValue = Double.pi anim?.duration = 0.5
- Add animation to View or Layer.
animView.layer.pop_add(anim, forKey: "basicAnimation")
NOTE: You can set any string as key
- Implement button action method.
func prepareForBasicAnimation() { let anim = POPBasicAnimation(propertyNamed: kPOPLayerRotation) anim?.fromValue = 0 anim?.toValue = Double.pi anim?.duration = 0.5 animView.layer.pop_add(anim, forKey: "basicAnimation") }
@IBAction func btnAnimationTap(_ sender: UIButton) { prepareForBasicAnimation() }
Spring Animation
Here in the demo app, I have given the Bouncing effect to Rounded View when it moves up and down. There is one UISlider to set springBounciness of UIView. POPSpringAnimation class is used for Spring Animation. POPSpringAnimation has properties like springBounciness, springSpeed to define the behavior of spring. We can apply constraints to the object we wish to move. We can modify the value of kPOPLayoutConstraintConstant to animate our interface object.
Steps:
- Import framework in your UIViewController class: import pop
- Create the outlet for ballView, slider and vertical center constraint constant of UIView. Your code should look like this:
@IBOutlet weak var ballView: UIView! @IBOutlet weak var slider: UISlider! @IBOutlet weak var ballCenterYConstraint: NSLayoutConstraint!
- Here is Bool for to know Up/Down status
var atTop: Bool = false
- In the viewDidLoad method, add the following line of code to set UISlider minimum and maximum value.
slider.minimumValue = 8.0 slider.maximumValue = 20.0
- Create POPSpringAnimation object by using NSLayoutConstraint Property.
let spring = POPSpringAnimation(propertyNamed: kPOPLayoutConstraintConstant)
- Set the toValue, springBounciness, springSpeed of animation.
spring?.toValue = 100 spring?.springBounciness = 8.0 spring?.springSpeed = 8
- Add animation to UIView vertical center constraint
ballCenterYConstraint.pop_add(spring, forKey: "moveUp")
- Same code for MoveDown, just change value to -100.
func animateBottom() { let spring = POPSpringAnimation(propertyNamed: kPOPLayoutConstraintConstant) spring?.toValue = -100 spring?.springBounciness = bounciness spring?.springSpeed = 8 ballCenterYConstraint.pop_add(spring, forKey: "moveDown") }
- Implement button action method.
func animateTop() { let spring = POPSpringAnimation(propertyNamed: kPOPLayoutConstraintConstant) spring?.toValue = 100 spring?.springBounciness = bounciness spring?.springSpeed = 8 ballCenterYConstraint.pop_add(spring, forKey: "moveUp") }
func animateBottom() { let spring = POPSpringAnimation(propertyNamed: kPOPLayoutConstraintConstant) spring?.toValue = -100 spring?.springBounciness = bounciness spring?.springSpeed = 8 ballCenterYConstraint.pop_add(spring, forKey: "moveDown") }
@IBAction func btnAnimationTap(_ sender: UIButton) { if atTop { animateBottom() } else { animateTop() } atTop = !atTop }
Decay Animation
Decay makes a movement to an eventual slow end. Decay use velocity as an input. In the demo app, I have given slow end effect to Rounded View. POPDecayAnimation class is used for Decay Animation. POPDecayAnimation has a property called velocity.
Steps:
- Import framework in your UIViewController class: import pop.
- Create the outlet variables for UIView and UISlider, as well as, Vertical Center Constraint Constant of UIView. Your outlet variable should look like this:
@IBOutlet weak var ballView: UIView! @IBOutlet weak var ballCenterYConstraint: NSLayoutConstraint!
- Create POPDecayAnimation object with using NSLayoutConstraint Property.
let spring = POPDecayAnimation(propertyNamed: kPOPLayoutConstraintConstant)
- Set the velocity of animation.
spring?.velocity = NSValue(cgPoint: CGPoint(x: -642.0, y: 0))
- Add animation to UIView vertical center constraint.
ballCenterYConstraint.pop_add(spring, forKey: "move")
- Implement button action method.
func prepareForDecayAnimation() { let spring = POPDecayAnimation(propertyNamed: kPOPLayoutConstraintConstant) spring?.velocity = NSValue(cgPoint: CGPoint(x: -642.0, y: 0)) rightBallCenterY.pop_add(spring, forKey: "move") }
@IBAction func btnAnimationTap(_ sender: UIButton) { rightBallCenterY.constant = 160 //Reset your View Position Y prepareForDecayAnimation() }
Delegation Handling
POP comes with a couple of delegate methods that alert you to particular events. We can take advantage of these when we are stacking animations in order to get the feeling you are looking for.
When one of these methods are called you can check the animation name to verify the animation in the one you need. For example:
let sprintAnimation = POPSpringAnimation(propertyNamed: kPOPViewScaleXY) sprintAnimation?.velocity = NSValue(cgPoint: CGPoint(x: 8.0, y: 8.0)) sprintAnimation?.springBounciness = 20.0 sprintAnimation?.name = "send" sprintAnimation?.delegate = self btnSend.pop_add(sprintAnimation, forKey: "sendAnimation")
Some POPAnimationDelegate are:
// Called on animation start. func pop_animationDidStart(_ anim: POPAnimation!) { if anim.name == "send" { // perform a new animation or action } } // Called when value meets or exceeds to value. func pop_animationDidReach(toValue anim: POPAnimation!) { if anim.name == "send" { // perform a new animation or action } } // Called on animation stop. func pop_animationDidStop(_ anim: POPAnimation!, finished: Bool) { if anim.name == "send" { // perform a new animation or action } } // Called each frame animation is applied func pop_animationDidApply(_ anim: POPAnimation!) { if anim.name == "send" { // perform a new animation or action } }
#Example Highlighted UITableViewCell
Go to your UITableViewCell class and override the setHighlighted method using the given code snippet:
override func setHighlighted(_ highlighted: Bool, animated: Bool) { super.setHighlighted(highlighted, animated: animated) if highlighted { let scaleAnimation = POPBasicAnimation(propertyNamed: kPOPViewScaleXY) scaleAnimation?.duration = 0.1// defaults to 0.4 scaleAnimation?.toValue = NSValue(cgPoint: CGPoint(x: 1.0, y: 1.0)) self.lblTitle.pop_add(scaleAnimation, forKey: "scaleAnimation") } else { let springAnimation = POPSpringAnimation(propertyNamed: kPOPViewScaleXY) springAnimation?.toValue = NSValue(cgPoint: CGPoint(x: 0.9, y: 0.9)) springAnimation?.velocity = NSValue(cgPoint: CGPoint(x: 2.0, y: 2.0)) springAnimation?.springBounciness = 20.0//from 1 to 20 self.lblTitle.pop_add(springAnimation, forKey: "springAnimation") } }
Properties To Know
- toValue: id // value type should match the property
- fromValue: id // value type should match the property
- velocity: id
- springBounciness: CGFloat // from 1 to 20
- springSpeed: CGFloat // from 1 to 20
- repeatForever: Bool // a convenient way to loop an animation
- duration: CFTimeInterval // defaults to 0.4
- beginTime: CFTimeInterval // if you want to delay the beginning of an animation
- name: NSString // identify the animation when delegate methods are called
- autoreverses: Bool // this will complete one full animation cycle; use repeateForever to loop the effect
Note: There are a number of predefined animation properties in the POPAnimatableProperty.h file that will help you make your animation.