• Stars
    star
    3,229
  • Rank 13,906 (Top 0.3 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created over 9 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easy to read and write chainable animations in Objective-C and Swift

language language Version Build Status MIT License Platform Platform

Whats new in version 3.x?

  • Swiftier syntax
  • Swift 4 support
  • Bug fixes and improvements

Whats new in version 2.x?

  • Re-architected from the ground up, no more hacking UIView 🛠
  • Added pre-animation and post-animation hooks for each animation step
  • Added pause and resume functionality
  • Added repeat animation functionality 🔂
  • Added friendly Swift interface in separate framework 🔥🕊

Whats wrong with animations?

CAAnimations and UIView animations are extremely powerful, but it is difficult to chain multiple animations together, especially while changing anchor points.

Furthermore, complicated animations are difficult to read.

Say I want to move myView 50 pixels to the right with spring and then change the background color with inward easing when the movement has finished:

The Old Way

    [UIView animateWithDuration:1.0
                          delay:0.0
         usingSpringWithDamping:0.8
          initialSpringVelocity:1.0
                        options:0 animations:^{
                            CGPoint newPosition = self.myView.frame.origin;
                            newPosition.x += 50;
                            self.myView.frame.origin = newPosition;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5
                              delay:0.0
                            options:UIViewAnimationOptionCurveEaseIn
                         animations:^{
            self.myView.backgroundColor = [UIColor purpleColor];
        } completion:nil];
    }];

Thats pretty gross huh... With JHChainableAnimations it is one line of code.

Using JHChainableAnimations

JHChainableAnimator *animator = [[JHChainableAnimator alloc] initWithView:self.myView];
animator.moveX(50).spring.thenAfter(1.0).makeBackground([UIColor purpleColor]).easeIn.animate(0.5);

There are also a lot of really good animation libraries out there such as RBBAnimation, DCAnimationKit, and PMTween, but they still fall short of having powerful chainable animations AND easy to read/write syntax.

Installation

There are a few ways you can add this framework to your project. The Objective-C framework is called JHChainableAnimations and the Swift framework is called ChainableAnimations. More notes on Swift usage can be found here

Cocoapods

Objective-C
pod 'JHChainableAnimations', '~> 3.0.1'

Then add the following:

#import <JHChainableAnimations/JHChainableAnimations.h>
Swift
pod 'ChainableAnimations', '~> 3.0.1'

Then add the following:

import ChainableAnimations

Carthage

Add the following to your Cartfile

github "jhurray/JHChainableAnimations" ~> 3.0.1
Objective-C

Add the JHChainableAnimations framework to your project.

Swift

Add the ChainableAnimations framework to your project.

Add to project Manually

Either clone the repo and manually add the Files in JHChainableAnimations

Usage

Creating an Animator

To create an instance of JHChainableAnimator you must call the initWithView: method.

JHChainableAnimator *animator = [[JHChainableAnimator alloc] initWithView:self.myView];

Animating

Chainable properties like moveX(x) must come between the view and the animate(t) function

Below is an example of how to double an objects size over the course of one second.

animator.makeScale(2.0).animate(1.0);

Combining Animations

If you want to move the view while you scale it, add another chainable property. Order is not important

animator.makeScale(2.0).moveXY(100, 50).animate(1.0);
// the same as animator.moveXY(100, 50).makeScale(2.0).animate(1.0);

A full list of chainable properties can be found here

Chaining Animations

To chain animations seperate the chains with the thenAfter(t) function.

Below is an example of how to scale and object for 0.5 seconds, and then move it for 1 second when that is done.

animator.makeScale(2.0).thenAfter(0.5).moveXY(100, 50).animate(1.0);

Animation Effects

To add an animation effect, call the effect method after the chainable property you want it to apply to.

Below is an example of scaling a view with a spring effect.

animator.makeScale(2.0).spring.animate(1.0);

If you add 2 to the same chainable property the second will cancel the first out.

animator.makeScale(2.0).bounce.spring.animate(1.0);
// The same as animator.makeScale(2.0).spring.animate(1.0);

A full list of animation effect properties can be found here

Anchoring

To anchor your view call an achoring method at some point in an animation chain. Like effects, calling one after another in the same chain will cancel the first out.

Below is an example of rotating a view around different anchor points

animator.rotateZ(180).anchorTopLeft.thenAfter(1.0).rotateZ(90).anchorCenter.animate(1.0);

// animator.rotateZ(90).anchorTopLeft.anchorCenter == animator.rotateZ(90).anchorCenter

A full list of anchor properties can be found here

Delays

To delay an animation call the wait(t) or delay(t) chainable property.

Below is an example of moving a view after a delay of 0.5 seconds

animator.moveXY(100, 50).wait(0.5).animate(1.0);
// The same as animator.moveXY(100, 50).delay(0.5).animate(1.0);

Completion

To run code after an animation finishes set the completionBlock property of your animator or call the animateWithCompletion(t, completion)*function.

animator.makeX(0).animateWithCompletion(1.0, ^{
	NSLog(@"Animation Done");
});

Is the same as:

animator.completionBlock = ^{
	NSLog(@"Animation Done");
};
animator.makeX(0).animate(1.0);

Repeating Animations

You can repeat an animation by replacing the thenAfter(time) method with the repeat(time, count) method. This will repeat the previously defined animations.

// The animator will double its scale 3 times for 0.5 seconds each before it calls `moveXY` and finishes the animation
animator.makeScale(2.0).repeat(0.5, 3).moveXY(100, 50).animate(1.0);

You can repeat the last part of an animation by calling animateWithRepeat(time, count).

// The animator will double its scale then rotate by 90 degrees 3 times for 1 second each.
animator.makeScale(2.0).thenAfter(0.5).rotate(90). animateWithRepeat(1.0, 3);

Pausing and Cancelling

To Pause the animation, call the pause method on the animator. When you call pause, the current animation in the chain will complete but nothing beyod that will be executed. You can use the isPaused and isAnimating readonly properties to inspect state. If an animation is paused but not stopped, it will still evaluate as animating.

To resume in a paused state, call the resume method on the animator.

To stop animation and clear state, call the stop method on the animator.

// In this case the `moveX` animation will execute but the `moveY` will not
// If `resume` is called `moveY` will be executed
// If `stop` is called, nothing will be executed and the animator will get a fresh state
animator.moveX(10).thenAfter(0.5).moveY(10).animate(0.5);
[animator pause];

Callbacks

You can hook into the different steps of the animation process by calling the preAnimationBlock(block), animationBlock(block), and postAnimationBlock(block) methods. All take a simple block void(^)() as an argument. Order of calling these in the animation chain does not matter.

animator.moveX(10).preAnimationBlock(^{ 
	NSLog(@"before the first animation");
 }).thenAfter(1.0).postAnimationBlock(^{
 	NSLog(@"After the second animation");
 }).moveY(10).animate(1.0);

Bezier Paths

You can also animate a view along a UIBezierPath. Create a UIBezierPath * instance, then add points or curves or lines to it and use it in a chainable property.

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:self.myView.center];
[path addLineToPoint:CGPointMake(25, 400)];
[path addLineToPoint:CGPointMake(300, 500)];
animator.moveOnPath(path).animate(1.0);

Animation effects do not work on path movements.

Using with Auto Layout

Transforms

Use the transform chainable properties. These are better for views constrained with Autolayout. You should not mix these with other chainable properties

animatorForViewWithConstraints.transformX(50).transformScale(2).animate(1.0);

Using with Swift

Using JHChainableAnimations with Swift is now a little more readable in version 2.x. I created a separate framework for swift that provides a class called ChainableAnimator. This is a thin wrapper over JHChainableAnimator that has a slightly more readable syntax.

let animator = ChainableAniamtor(view: myView)
animator.moveX(x: 50).thenAfter(t: 1.0).rotate(angle: 360).bounce.animate(t:1.0)

All Objective-C methods map to a swift method.

Chainable Properties

Property Takes a... Usage
- (JHChainableRect) makeFrame; CGRect animator.makeFrame(rect).animate(1.0);
- (JHChainableRect) makeBounds; CGRect animator.makeBounds(rect).animate(1.0);
- (JHChainableSize) makeSize; (CGFloat: width, CGFloat: height) animator.makeSize(10, 20).animate(1.0);
- (JHChainablePoint) makeOrigin; (CGFloat: x, CGFloat: y) animator.makeOrigin(10, 20).animate(1.0);
- (JHChainablePoint) makeCenter; (CGFloat: x, CGFloat: y) animator.makeCenter(10, 20).animate(1.0);
- (JHChainableFloat) makeX; (CGFloat: f) animator.makeX(10).animate(1.0);
- (JHChainableFloat) makeY; (CGFloat: f) animator.makeY(10).animate(1.0);
- (JHChainableFloat) makeWidth; (CGFloat: f) animator.makeWidth(10).animate(1.0);
- (JHChainableFloat) makeHeight; (CGFloat: f) animator.makeHeight(10).animate(1.0);
- (JHChainableFloat) makeOpacity; (CGFloat: f) animator.makeOpacity(10).animate(1.0);
- (JHChainableColor) makeBackground; (UIColor: color) animator.makeBackground(color).animate(1.0);
- (JHChainableColor) makeBorderColor; (UIColor: color) animator.makeBorderColor(color).animate(1.0);
- (JHChainableFloat) makeBorderWidth; (CGFloat: f) animator.makeBorderWidth(3.0).animate(1.0);
- (JHChainableFloat) makeCornerRadius; (CGFloat: f) animator.makeCornerRadius(3.0).animate(1.0);
- (JHChainableFloat) makeScale; (CGFloat: f) animator.makeScale(2.0).animate(1.0);
- (JHChainableFloat) makeScaleX; (CGFloat: f) animator.makeScaleX(2.0).animate(1.0);
- (JHChainableFloat) makeScaleY; (CGFloat: f) animator.makeScaleY(2.0).animate(1.0);
- (JHChainablePoint) makeAnchor; (CGFloat: x, CGFloat: y) animator.makeAnchor(0.5, 0.5).animate(1.0);
- (JHChainableFloat) moveX; (CGFloat: f) animator.moveX(50).animate(1.0)
- (JHChainableFloat) moveY; (CGFloat: f) animator.moveY(50).animate(1.0)
- (JHChainablePoint) moveXY; (CGFloat: x, CGFloat: y) animator.moveXY(100, 50).animate(1.0)
- (JHChainableFloat) moveHeight; (CGFloat: f) animator.moveHeight(50).animate(1.0)
- (JHChainableFloat) moveWidth; (CGFloat: f) animator.moveWidth(50).animate(1.0)
- (JHChainableDegrees) rotateX; (CGFloat: angle) #not radians! animator.rotateX(360).animate(1.0);
- (JHChainableDegrees) rotateY; (CGFloat: angle) #not radians! animator.rotateY(360).animate(1.0);
- (JHChainableDegrees) rotateZ; (CGFloat: angle) #not radians! animator.rotateZ(360).animate(1.0);
- (JHChainablePolarCoordinate) movePolar; (CGFloat: radius, CGFloat: angle) animator.movePolar(30, 90).animate(1.0);
- (JHChainableBezierPath) moveOnPath; (UIBezierPath *path) animator.moveOnPath(path).animate(1.0);
- (JHChainableBezierPath) moveAndRotateOnPath; (UIBezierPath *path) animator.moveAndRotateOnPath(path).animate(1.0);
- (JHChainableBezierPath) moveAndReverseRotateOnPath; (UIBezierPath *path) animator.moveAndReverseRotateOnPath(path).animate(1.0);
- (JHChainableFloat) transformX; (CGFloat f) animator.transformX(50).animate(1.0);
- (JHChainableFloat) transformX; (CGFloat f) animator.transformX(50).animate(1.0);
- (JHChainableFloat) transformY; (CGFloat f) animator.transformY(50).animate(1.0);
- (JHChainableFloat) transformZ; (CGFloat f) animator.transformZ(50).animate(1.0);
- (JHChainablePoint) transformXY; (CGFloat x, CGFloat y) animator.transformXY(50, 100).animate(1.0);
- (JHChainableFloat) transformScale; (CGFloat f) animator.transformScale(50).animate(1.0);
- (JHChainableFloat) transformScaleX; (CGFloat f) animator.transformScaleX(50).animate(1.0);
- (JHChainableFloat) transformScaleY; (CGFloat f) animator.transformScaleY(50).animate(1.0);
- (JHChainableAnimator *) transformIdentity; Nothing animator.transformIdentity.animate(1.0);

Animation Effects

A quick look at these funcs can be found here

These animation functions were taken from a cool keyframe animation library that can be found here

They are based off of JQuery easing functions that can be found here

Anchoring

Info on anchoring can be found here

To Do

I have gotten a ton of great suggestions of what to do next. If you think this is missing anything please let me know! The following is what I plan on working on in no particular order.

  • OSX port
  • Constraint animator

Contact Info && Contributing

Feel free to email me at [email protected]. I'd love to hear your thoughts on this, or see examples where this has been used.

MIT License

More Repositories

1

SelectableTextView

A text view that supports selection and expansion
Swift
634
star
2

EZLayout

A new take on iOS layouts using percentages. Goodbye autolayout.
Objective-C
264
star
3

Ladybug

A powerful model framework for Swift 4
Swift
147
star
4

JHPullToRefreshKit

Abstract classes to easily create pull to refresh controls
Objective-C
69
star
5

Swift2-Protocol-Extension-Example

Playground showing how to use swift2 protocol extensions to render errors in UIViews and UIViewControllers without subclassing
Swift
37
star
6

Transform.swift

A Swiftier way to transform views
Swift
26
star
7

SQLiteModel

Easiest way to persist data in Swift
Swift
25
star
8

Illuminotchi

They're watching 👀
Swift
22
star
9

iOS7AnimatedMapOverlay

A sample project for adding animated overlays at points on the map.
Objective-C
22
star
10

AnimatedLabelExample

An example project showing how to create and use animated text like the slide lock for iOS devices.
Objective-C
15
star
11

Tuneder

An app to to make quick playlists with a tinder style card picker view. EZLayout is used for layout.
Objective-C
6
star
12

BALoadingAnimations

A wrapper over loading animations that makes it simple to incorporate into your project. Supports multiple animations and makes it easy to create/add new ones.
Objective-C
3
star
13

iOSCustomTransitions

Custom animation transition manager and base VC for iOS apps.
Objective-C
2
star
14

Beginning-iOS-in-Swift-Workshop

Blank template project for the beginning iOS seminar I ran for Yahoo at the University of Michigan
Objective-C
2
star
15

StudyBunny

Creating Study Groups across College Campuses
Objective-C
2
star
16

iOS8TodayExtensionExample

A simple today extension for iOS8
Objective-C
1
star
17

CodePath-TwitterClient

A Twitter client for the CodePath class I taught at Yahoo
Objective-C
1
star
18

CornerSlideNavigation

An animated navigation tool that can be used in place of a tab bar.
Objective-C
1
star
19

Flask-Pewee-Knockout-Barebones

A lightweight web app framework using flask, peewee, and knockout.js. Also includes database setup and a cache.
Python
1
star