Easily build advanced custom animations on iOS.

Last update: Jun 22, 2022

INTUAnimationEngine

Build Status Test Coverage Version Platform License

INTUAnimationEngine makes it easy to build advanced custom animations on iOS.

INTUAnimationEngine provides a friendly interface to drive custom animations using a CADisplayLink, inspired by the UIView block-based animation API. It enables interactive animations (normally driven by user input, such as a pan or pinch gesture) to run automatically over a given duration. It can also be used to get a callback every frame of an animation.

INTUAnimationEngine includes an extensive library of easing functions that can be used to customize animation timing, as well as a complete library of interpolation functions to animate any type of value or property including those that are not animatable by Core Animation.

The project also includes a standalone spring physics library to simulate damped harmonic motion. This is used under the hood to power a spring animation API on INTUAnimationEngine that allows full control over the damping, stiffness, and mass parameters. Since the spring solver is a completely independent and generic library implemented in pure C, it can be used on its own for many other applications apart from animation.

Installation

INTUAnimationEngine requires iOS 5.0 or later.

Using CocoaPods

  1. Add the pod INTUAnimationEngine to your Podfile.
pod 'INTUAnimationEngine'
  1. Run pod install from Terminal, then open your app's .xcworkspace file to launch Xcode.
  2. Import the INTUAnimationEngine.h header. Typically, this should be written as #import <INTUAnimationEngine/INTUAnimationEngine.h>.

Installing the Spring Solver Library Only

The Spring Solver used by INTUAnimationEngine is available as a standalone C library, where it can be used for other applications (including ones that are not related to animation). The Spring Solver has its own CocoaPods subspec so that it can be installed separately from the rest of the INTUAnimationEngine project. To install the Spring Solver only, add the following line to your Podfile:

pod 'INTUAnimationEngine/SpringSolver'

Note that installing INTUAnimationEngine using pod 'INTUAnimationEngine' automatically includes the Spring Solver library as a dependency.

Manually from GitHub

  1. Download the contents of the INTUAnimationEngine directory.
  2. Add all the files to your Xcode project (drag and drop is easiest).
  3. Import the INTUAnimationEngine.h header.

Usage

The primary difference between INTUAnimationEngine and the UIView animation methods is how the animations block works. With the UIView methods, the animations block is only executed once, and the changes made to views within this block represent the new state at the end of the animation.

With INTUAnimationEngine, the animations block is executed many times during the animation (once per frame), and each time it is executed, your code inside the block should update the state of views based upon the current value of the percentage or progress passed into the block. Typically, you'll want to use one of the interpolation functions included in this library to help generate all the intermediate values between the start and end states for a given property.

Animation Engine

There are a few different API methods on INTUAnimationEngine that can be used to start an animation.

Without Easing (Linear)

+ (INTUAnimationID)animateWithDuration:(NSTimeInterval)duration
                                 delay:(NSTimeInterval)delay
                            animations:(void (^)(CGFloat percentage))animations
                            completion:(void (^)(BOOL finished))completion;

This method will start an animation that calls the animations block each frame of the animation, passing in a percentage value that represents the animation's current percentage complete. The completion block will be executed when the animation completes, with the finished parameter indicating whether the animation was canceled.

With Easing

+ (INTUAnimationID)animateWithDuration:(NSTimeInterval)duration
                                 delay:(NSTimeInterval)delay
                                easing:(INTUEasingFunction)easingFunction
                            animations:(void (^)(CGFloat progress))animations
                            completion:(void (^)(BOOL finished))completion;

This method will start an animation that calls the animations block each frame of the animation, passing in a progress value that represents the current progress of the animation (taking into account the easing function). The easingFunction can be any of the easing functions in INTUEasingFunctions.h, or a block that defines a custom easing curve. The completion block will be executed when the animation completes, with the finished parameter indicating whether the animation was canceled.

There is also another variant of the above method that takes an options: parameter, which is a mask of INTUAnimationOptions. This can be used to repeat or autoreverse animations.

Using a Spring

+ (INTUAnimationID)animateWithDamping:(CGFloat)damping
                            stiffness:(CGFloat)stiffness
                                 mass:(CGFloat)mass
                                delay:(NSTimeInterval)delay
                           animations:(void (^)(CGFloat progress))animations
                           completion:(void (^)(BOOL finished))completion;

This method will start a spring animation that calls the animations block each frame of the animation, passing in a progress value that represents the current progress of the animation. The animation will simulate the physics of a spring-mass system with the specified properties:

  • damping – The amount of friction. Must be greater than or equal to zero. If exactly zero, the harmonic motion will continue indefinitely. Typical range: 1.0 to 30.0
  • stiffness – The stiffness of the spring. Must be greater than zero. Typical range: 1.0 to 500.0
  • mass – The amount of mass being moved by the spring. Must be greater than zero. Typical range: 0.1 to 10.0

Note that the total duration of the animation is determined by simulating a spring-mass system with the above parameters until it reaches a resting state. The completion block will be executed when the animation completes, with the finished parameter indicating whether the animation was canceled.

Canceling Animations

+ (void)cancelAnimationWithID:(INTUAnimationID)animationID;

When starting an animation, you can store the returned animation ID, and pass it to the above method to cancel the animation before it completes. If the animation is canceled, the completion block will execute with finished parameter equal to NO.

Easing Functions

INTUEasingFunctions.h is a library of standard easing functions. Here's a handy cheat sheet that includes visualizations and animation demos for these functions.

Interpolation Functions

INTUInterpolationFunctions.h is a library of interpolation functions.

Proximal Interpolation

For discrete values (where linear interpolation does not make sense), there are two proxmial interpolation functions. For example:

INTUInterpolateDiscrete(NSTextAlignmentLeft, NSTextAlignmentRight, progress)
// Returns NSTextAlignmentLeft when progress is < 0.5, NSTextAlignmentRight otherwise

[INTUInterpolateDiscreteValues(@[@(NSTextAlignmentLeft), @(NSTextAlignmentCenter), @(NSTextAlignmentRight)], progress) integerValue]
// Returns NSTextAlignmentLeft, then NSTextAlignmentCenter, and finally NSTextAlignmentRight as progress increases from 0.0 to 1.0

Linear Interpolation

For continuous values, there are a variety of linear interpolation functions. The following types are supported:

  • CGFloat
  • CGPoint
  • CGSize
  • CGRect
  • CGVector
  • UIOffset
  • UIEdgeInsets
  • UIColor / CGColor

There is also an untyped function INTUInterpolate() that takes values of type id and returns an interpolated value by automatically determining the type of the values. Proximal interpolation is used if the value types do not match, or if linear interpolation isn't supported for their type.

CGAffineTransform & CATransform3D

There are no functions that directly interpolate transforms. This is by design: linear interpolation of raw matrices often yields unexpected or invalid results. To interpolate between two transforms, decompose them into their translation, rotation, and scale components:

CGFloat rotation = INTUInterpolateCGFloat(0.0, M_PI, progress);
view.transform = CGAffineTransformMakeRotation(rotation);
// view will rotate from upright (progress = 0.0) to upside down (progress = 1.0)

You can concatenate transforms to combine them:

CGFloat rotation = INTUInterpolateCGFloat(0.0, M_PI, progress);
CGFloat scale = INTUInterpolateCGFloat(1.0, 0.5, progress);
view.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale), CGAffineTransformMakeRotation(rotation));
// view will rotate from upright and full size (progress = 0.0), to upside down and half size (progress = 1.0)
UIColor / CGColor

When interpolating between two colors, both colors must be in the same color space (grayscale, RGB, or HSB). Interpolating between colors in the HSB color space will generally yield better visual results than the RGB color space.

[UIColor colorWithWhite:1.0 alpha:1.0] // Grayscale color space; white
[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0] // RGB color space; white
[UIColor colorWithHue:0.0 saturation:0.0 brightness:1.0 alpha:1.0] // HSB color space; white

Spring Solver

The SpringSolver directory in the project contains a spring physics library to simulate damped harmonic motion, based on the spring solver that powers Facebook's Pop. The INTUAnimationEngine spring solver has been extensively refactored for simplicity and performance, and as a fully independent pure C library is highly portable to any platform and can be leveraged for other use cases beyond animation.

Example Project

An example project is provided. It requires Xcode 6 and iOS 6.0 or later.

Issues & Contributions

Please open an issue here on GitHub if you have a problem, suggestion, or other comment.

Pull requests are welcome and encouraged! There are no official guidelines, but please try to be consistent with the existing code style.

License

INTUAnimationEngine is provided under the MIT license. The spring solver library within the project is provided under a BSD license.

INTU on GitHub

Check out more iOS and OS X open source projects from Intuit!

GitHub

https://github.com/intuit/AnimationEngine
You might also like...

A UICollectionViewLayout subclass that adds custom transitions/animations to the UICollectionView without effecting your existing code.

A UICollectionViewLayout subclass that adds custom transitions/animations to the UICollectionView without effecting your existing code.

AnimatedCollectionViewLayout Normally a UICollectionView has no transition effects when you scroll from one item to another. There are lots of ways to

Jun 23, 2022

Custom MacBook keyboard backlight animations

Custom MacBook keyboard backlight animations

KBPulse Pulse the backlight on your Mac keyboard Demo Configuration Configuration files (.json) are stored in ~/Documents/KBPulse. (This location will

Apr 5, 2022

Physics-based animations for iOS, tvOS, and macOS.

Advance An animation library for iOS, tvOS, and macOS that uses physics-based animations (including springs) to power interactions that move and respo

Jun 21, 2022

An iOS library to natively render After Effects vector animations

An iOS library to natively render After Effects vector animations

Lottie for iOS, macOS (and Android and React Native) View documentation, FAQ, help, examples, and more at airbnb.io/lottie Lottie is a mobile library

Jun 21, 2022

A library to simplify iOS animations in Swift.

Updated for Swift 4.2 Requires Xcode 10 and Swift 4.2. Installation Drop in the Spring folder to your Xcode project (make sure to enable "Copy items i

Jun 21, 2022

Sample way of integrating animations into a design system for iOS app projects.

Animations in Design System The project presents a sample way of integrating animations into a design system for iOS developers. Project setup A sampl

Nov 26, 2021

MotionBlur allows you to add motion blur effect to iOS animations.

MotionBlur allows you to add motion blur effect to iOS animations.

MotionBlur MotionBlur allows you to add motion blur effect to your animations (currently only position's change). See the accompanying blog post to le

Apr 22, 2022

Wave is a spring-based animation engine for iOS that makes it easy to create fluid, interruptible animations that feel great.

Wave is a spring-based animation engine for iOS that makes it easy to create fluid, interruptible animations that feel great.

Wave is a spring-based animation engine for iOS and iPadOS. It makes it easy to create fluid, interactive, and interruptible animations that feel great.

Jun 21, 2022

Stagehand provides a modern, type-safe API for building animations on iOS

Stagehand Stagehand provides a modern, type-safe API for building animations on iOS. Stagehand is designed around a set of core ideas: Composition of

Apr 26, 2022
Comments
  • 1. Modifying activeAnimations while enumerating through it

    Howdy! Not sure if I'm going about this in a weird way, but I must be somehow calling the addAnimation/removeAnimationWithID while tickActiveAnimations is being called, making my app crash.

    My basic solution is to make two more collections that modify activeAnimations after it's done looping.

    @property (nonatomic, strong) NSMutableArray *animationsToAdd;
    @property (nonatomic, strong) NSMutableDictionary *animationsToRemove;
    

    Insert/remove the animations immediately after the for loop in tickActiveAnimations

    for (JotINTUAnimation *anim in self.animationsToAdd) {
        anim.startTime = CACurrentMediaTime();
        [self.activeAnimations setObject:anim forKey:@(anim.animationID)];
    }
    
    for (NSNumber *animationID in [self.animationsToRemove keyEnumerator]) {
        JotINTUAnimation *animation = [self.activeAnimations objectForKey:animationID];
        [animation complete:[[self.animationsToRemove objectForKey:animationID] boolValue]];
        [self.activeAnimations removeObjectForKey:animationID];
        if ([self.activeAnimations count] == 0) {
            self.displayLink.paused = YES;
        }
    }
    
    [self.animationsToRemove removeAllObjects];
    [self.animationsToAdd removeAllObjects];
    

    Rewrite the basic addAnimation and removeAnimationWithID methods

    - (void)addAnimation:(JotINTUAnimation *)animation
    {
        if ([self.activeAnimations count] == 0) {
            self.displayLink.paused = NO;
        }
    
        [self.animationsToAdd addObject:animation];
    }
    
    - (void)removeAnimationWithID:(JotINTUAnimationID)animationID didFinish:(BOOL)finished
    {
        [self.animationsToRemove setObject:@(finished) forKey:@(animationID)];
    }
    

    This is my first issue I've ever created, if you want me to submit a PR let me know. Also, if I am totally overengineering this problem, let me know that as well :D

    Reviewed by Naxum at 2015-08-05 20:33
  • 2. Swift compatibility

    Trying to call INTUAnimationEngine.animateWithDuration(1.0, delay: 0.0, easing: INTUEaseInBounce, animations: nil, completion: nil) from swift code but getting "Extra argument 'easing' in call" error. Probably there is something with this line from INTUEasingFunctions.h:

    typedef CGFloat (*INTUEasingFunction)(CGFloat);

    How should I use this method from swift code?

    Reviewed by okla at 2014-10-13 09:41
A Swift library to take the power of UIView.animateWithDuration(_:, animations:...) to a whole new level - layers, springs, chain-able animations and mixing view and layer animations together!
A Swift library to take the power of UIView.animateWithDuration(_:, animations:...) to a whole new level - layers, springs, chain-able animations and mixing view and layer animations together!

ver 2.0 NB! Breaking changes in 2.0 - due to a lot of requests EasyAnimation does NOT automatically install itself when imported. You need to enable i

Jun 18, 2022
Advanced Natural Motion Animations, Simple Blocks Based Syntax
Advanced Natural Motion Animations, Simple Blocks Based Syntax

FlightAnimator Moved to Swift 3.1 Support: For Swift 3.1 - Use tag Version 0.9.9 See Installation Instructions for clarification Introduction FlightAn

Feb 8, 2022
A port of SwiftUILab's Advanced Animations that also supports macOS
A port of SwiftUILab's Advanced Animations that also supports macOS

SwiftUILab Advanced Animations on the Mac as well A port of SwiftUILab's Advanced Animations that also supports macOS Here's the Ghist of the original

Apr 27, 2022
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.

wobbly See Wobbly in action (examples) Add a drop of honey ?? to your project wobbly has a bunch of cool, fun, and easy to use iOS animations for you

Dec 23, 2021
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.
(Animate CSS) animations for iOS. An easy to use library of iOS animations. As easy to use as an easy thing.

wobbly See Wobbly in action (examples) Add a drop of honey ?? to your project wobbly has a bunch of cool, fun, and easy to use iOS animations for you

Dec 23, 2021
A collection of animations for iOS. Simple, just add water animations.
A collection of animations for iOS. Simple, just add water animations.

DCAnimationKit A collection of animations for iOS Simply, just add water! DCAnimationKit is a category on UIView to make animations easy to perform. E

Jun 13, 2022
Build complex, conducted animations declaratively without manually managing state.
Build complex, conducted animations declaratively without manually managing state.

Maestro Build complex, conducted animations declaratively without manually managing state. Code struct AnimatedPieChart: View { private enum Trim

Dec 29, 2021
Easily pause and resume SwiftUI animations
Easily pause and resume SwiftUI animations

swiftui-pausable-animation Easily pause and resume SwiftUI animations! Installation This component is distributed as a Swift package. Just add this re

May 23, 2022
A library of custom iOS View Controller Animations and Interactions.
A library of custom iOS View Controller Animations and Interactions.

RZTransitions is a library to help make iOS7 custom View Controller transitions slick and simple. Installation CocoaPods (Recommended) Add the followi

Jun 17, 2022
Ease is an event driven animation system that combines the observer pattern with custom spring animations as observers
Ease is an event driven animation system that combines the observer pattern with custom spring animations as observers

Ease is an event driven animation system that combines the observer pattern with custom spring animations as observers. It's magic. Features Animate a

Jun 20, 2022