Convert Figma logo to code with AI

facebookarchive logopop

An extensible iOS and OS X animation library, useful for physics-based interactions.

19,660
2,881
19,660
58

Top Related Projects

24,321

Reactive Programming in Swift

47,834

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.

67,285

The Swift Programming Language

6,450

The iOS framework that grows only as fast as its documentation

Quick Overview

Pop is an extensible animation engine for iOS, macOS, and tvOS developed by Facebook. It provides a powerful and flexible framework for creating smooth, interactive animations in Apple's ecosystem. Pop can be used to create both basic and complex animations, offering a more dynamic alternative to UIKit's animation capabilities.

Pros

  • Highly performant, utilizing Core Animation for efficient rendering
  • Supports spring animations, decay animations, and custom animations
  • Easily extensible, allowing developers to create custom animation types
  • Works well with existing UIKit and AppKit components

Cons

  • Learning curve can be steep for developers used to UIKit animations
  • Documentation could be more comprehensive
  • No longer actively maintained by Facebook (archived repository)
  • Some reported issues with memory management in complex animations

Code Examples

  1. Creating a basic spring animation:
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY];
anim.toValue = [NSValue valueWithCGSize:CGSizeMake(2.0, 2.0)];
anim.springBounciness = 20.0;
anim.springSpeed = 20.0;
[myView pop_addAnimation:anim forKey:@"spring"];
  1. Implementing a decay animation:
POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
anim.velocity = @(1000);
anim.deceleration = 0.998;
[myLayer pop_addAnimation:anim forKey:@"decay"];
  1. Creating a custom animation:
POPCustomAnimation *anim = [POPCustomAnimation animationWithBlock:^BOOL(id target, POPCustomAnimation *animation) {
    CGFloat progress = animation.currentTime / animation.duration;
    ((UIView *)target).alpha = progress;
    return progress < 1.0;
}];
[myView pop_addAnimation:anim forKey:@"custom"];

Getting Started

To use Pop in your project:

  1. Install via CocoaPods by adding to your Podfile:

    pod 'pop'
    
  2. Run pod install in your project directory.

  3. Import Pop in your source files:

    #import <POP/POP.h>
    
  4. Start creating animations using the POPAnimation classes as shown in the code examples above.

Competitor Comparisons

24,321

Reactive Programming in Swift

Pros of RxSwift

  • Comprehensive reactive programming framework for Swift
  • Supports a wide range of reactive operations and transformations
  • Strong community support and extensive documentation

Cons of RxSwift

  • Steeper learning curve for developers new to reactive programming
  • Can lead to increased code complexity for simple tasks
  • Potential performance overhead for heavy observables

Code Comparison

RxSwift:

Observable.from([1, 2, 3, 4, 5])
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .subscribe(onNext: { print($0) })

pop:

POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPositionY];
anim.toValue = @(200);
anim.springBounciness = 4;
anim.springSpeed = 12;
[layer pop_addAnimation:anim forKey:@"spring"];

Key Differences

  • RxSwift focuses on reactive programming and data flow, while pop specializes in animations
  • RxSwift is written in Swift, whereas pop is primarily in Objective-C
  • RxSwift offers a more extensive set of features for general app architecture, while pop is more targeted towards UI interactions and animations

Use Cases

  • Choose RxSwift for complex data flows, asynchronous programming, and reactive app architecture
  • Opt for pop when dealing specifically with advanced animations and dynamic UI behaviors
47,834

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

Pros of RxJava

  • Broader scope: RxJava is a comprehensive reactive programming library for Java, while Pop is focused on animation for iOS
  • Cross-platform: RxJava can be used on various platforms, including Android and server-side applications
  • Rich ecosystem: Extensive documentation, community support, and integration with other libraries

Cons of RxJava

  • Steeper learning curve: Reactive programming paradigm can be challenging for developers new to the concept
  • Potential overhead: May introduce unnecessary complexity for simpler use cases
  • Memory management: Requires careful handling of subscriptions to avoid memory leaks

Code Comparison

Pop (Objective-C):

POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 400, 400)];
[layer pop_addAnimation:anim forKey:@"size"];

RxJava (Java):

Observable.interval(1, TimeUnit.SECONDS)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(tick -> updateUI());

While both libraries deal with asynchronous operations, Pop focuses on animations, whereas RxJava provides a more general-purpose reactive programming model. The code snippets demonstrate their different use cases and syntax.

Cocoa framework and Obj-C dynamism bindings for ReactiveSwift.

Pros of ReactiveCocoa

  • Provides a comprehensive framework for reactive programming in Objective-C and Swift
  • Offers powerful abstractions for handling asynchronous events and data streams
  • Integrates well with Apple's Combine framework for Swift

Cons of ReactiveCocoa

  • Steeper learning curve compared to Pop's simpler animation-focused API
  • May introduce unnecessary complexity for projects that don't require extensive reactive programming

Code Comparison

ReactiveCocoa:

let searchResults = searchTextField.reactive.continuousTextValues
    .throttle(0.3, on: QueueScheduler.main)
    .flatMap(.latest) { (query: String) -> SignalProducer<[SearchResult], Never> in
        return API.search(query)
    }

Pop:

POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
anim.toValue = [NSValue valueWithCGSize:CGSizeMake(2.0, 2.0)];
anim.springBounciness = 18;
[layer pop_addAnimation:anim forKey:@"scale"];

Summary

ReactiveCocoa is a powerful framework for reactive programming, offering extensive capabilities for handling asynchronous events and data streams. It's well-suited for complex applications that benefit from reactive paradigms. Pop, on the other hand, focuses specifically on animations, providing a simpler API for creating dynamic and interactive user interfaces. The choice between the two depends on the project's requirements and the developer's familiarity with reactive programming concepts.

67,285

The Swift Programming Language

Pros of Swift

  • Comprehensive language ecosystem with standard library and tooling
  • Actively maintained and developed by Apple and open-source community
  • Supports multiple platforms beyond iOS (macOS, Linux, Windows)

Cons of Swift

  • Steeper learning curve for beginners compared to Objective-C
  • Larger codebase and more complex project structure
  • Frequent language updates may require code migrations

Code Comparison

Swift:

struct Person {
    let name: String
    var age: Int
}

let person = Person(name: "John", age: 30)
print("Name: \(person.name), Age: \(person.age)")

Pop:

@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end

Person *person = [[Person alloc] init];
person.name = @"John";
person.age = 30;
NSLog(@"Name: %@, Age: %ld", person.name, (long)person.age);

Swift offers a more concise and modern syntax compared to Pop's Objective-C, with features like type inference and string interpolation. However, Pop focuses specifically on animation frameworks, while Swift is a general-purpose programming language with a broader scope and application range.

6,450

The iOS framework that grows only as fast as its documentation

Pros of Nimbus

  • More comprehensive framework with a wider range of UI components and utilities
  • Better documentation and examples for developers
  • Active development and maintenance

Cons of Nimbus

  • Steeper learning curve due to its broader scope
  • Potentially larger footprint in terms of code size and memory usage
  • Less focused on animation compared to Pop

Code Comparison

Nimbus (UIView animation):

[NIViewAnimationBuilder animate:^{
    view.alpha = 0.0f;
} completion:^{
    [view removeFromSuperview];
}];

Pop (UIView animation):

POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
anim.toValue = @(0.0);
anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
    [view removeFromSuperview];
};
[view pop_addAnimation:anim forKey:@"fade"];

Nimbus offers a more concise syntax for basic animations, while Pop provides more granular control over animation properties and behaviors. Pop is specifically designed for high-performance animations, whereas Nimbus covers a broader range of UI development needs.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

pop

Pop is an extensible animation engine for iOS, tvOS, and OS X. In addition to basic static animations, it supports spring and decay dynamic animations, making it useful for building realistic, physics-based interactions. The API allows quick integration with existing Objective-C or Swift codebases and enables the animation of any property on any object. It's a mature and well-tested framework that drives all the animations and transitions in Paper.

Build Status

Installation

Pop is available on CocoaPods. Just add the following to your project Podfile:

pod 'pop', '~> 1.0'

Bugs are first fixed in master and then made available via a designated release. If you tend to live on the bleeding edge, you can use Pop from master with the following Podfile entry:

pod 'pop', :git => 'https://github.com/facebook/pop.git'

Framework (manual)

By adding the project to your project and adding pop.embedded framework to the Embedded Binaries section on the General tab of your app's target, you can set up pop in seconds! This also enables @import pop syntax with header modules.

Note: because of some awkward limitations with Xcode, embedded binaries must share the same name as the module and must have .framework as an extension. This means that you'll see three pop.frameworks when adding embedded binaries (one for OS X, one for tvOS, and one for iOS). You'll need to be sure to add the right one; they appear identically in the list but note the list is populated in order of targets. You can verify the correct one was chosen by checking the path next to the framework listed, in the format <configuration>-<platform> (e.g. Debug-iphoneos).

Embedded Binaries

Note 2: this method does not currently play nicely with workspaces. Since targets can only depend on and embed products from other targets in the same project, it only works when pop.xcodeproj is added as a subproject to the current target's project. Otherwise, you'll need to manually set the build ordering in the scheme and copy in the product.

Static Library (manual)

Alternatively, you can add the project to your workspace and adopt the provided configuration files or manually copy the files under the pop subdirectory into your project. If installing manually, ensure the C++ standard library is also linked by including -lc++ to your project linker flags.

Usage

Pop adopts the Core Animation explicit animation programming model. Use by including the following import:

Objective-C

#import <pop/POP.h>

or if you're using the embedded framework:

@import pop;

Swift

import pop

Start, Stop & Update

To start an animation, add it to the object you wish to animate:

Objective-C

POPSpringAnimation *anim = [POPSpringAnimation animation];
...
[layer pop_addAnimation:anim forKey:@"myKey"];

Swift

let anim = POPSpringAnimation()
...
layer.pop_add(anim, forKey: "myKey")

To stop an animation, remove it from the object referencing the key specified on start:

Objective-C

[layer pop_removeAnimationForKey:@"myKey"];

Swift

layer.pop_removeAnimation(forKey: "myKey")

The key can also be used to query for the existence of an animation. Updating the toValue of a running animation can provide the most seamless way to change course:

Objective-C

anim = [layer pop_animationForKey:@"myKey"];
if (anim) {
  /* update to value to new destination */
  anim.toValue = @(42.0);
} else {
  /* create and start a new animation */
  ....
}

Swift

if let anim = layer.pop_animation(forKey: "myKey") as? POPSpringAnimation {
    /* update to value to new destination */
    anim.toValue = 42.0
} else {
    /* create and start a new animation */
    ....
}

While a layer was used in the above examples, the Pop interface is implemented as a category addition on NSObject. Any NSObject or subclass can be animated.

Types

There are four concrete animation types: spring, decay, basic and custom.

Spring animations can be used to give objects a delightful bounce. In this example, we use a spring animation to animate a layer's bounds from its current value to (0, 0, 400, 400):

Objective-C

POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
anim.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 400, 400)];
[layer pop_addAnimation:anim forKey:@"size"];

Swift

if let anim = POPSpringAnimation(propertyNamed: kPOPLayerBounds) {
    anim.toValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: 400, height: 400))
    layer.pop_add(anim, forKey: "size")
}

Decay animations can be used to gradually slow an object to a halt. In this example, we decay a layer's positionX from it's current value and velocity 1000pts per second:

Objective-C

POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
anim.velocity = @(1000.);
[layer pop_addAnimation:anim forKey:@"slide"];

Swift

if let anim = POPDecayAnimation(propertyNamed: kPOPLayerPositionX) {
    anim.velocity = 1000.0
    layer.pop_add(anim, forKey: "slide")
}

Basic animations can be used to interpolate values over a specified time period. To use an ease-in ease-out animation to animate a view's alpha from 0.0 to 1.0 over the default duration:

Objective-C

POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.fromValue = @(0.0);
anim.toValue = @(1.0);
[view pop_addAnimation:anim forKey:@"fade"];

Swift

if let anim = POPBasicAnimation(propertyNamed: kPOPViewAlpha) {
    anim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    anim.fromValue = 0.0
    anim.toValue = 1.0
    view.pop_add(anim, forKey: "fade")
}

POPCustomAnimation makes creating custom animations and transitions easier by handling CADisplayLink and associated time-step management. See header for more details.

Properties

The property animated is specified by the POPAnimatableProperty class. In this example we create a spring animation and explicitly set the animatable property corresponding to -[CALayer bounds]:

Objective-C

POPSpringAnimation *anim = [POPSpringAnimation animation];
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerBounds];

Swift

let anim = POPSpringAnimation()
if let property = POPAnimatableProperty.property(withName: kPOPLayerBounds) as? POPAnimatableProperty {
    anim.property = property
}

The framework provides many common layer and view animatable properties out of box. You can animate a custom property by creating a new instance of the class. In this example, we declare a custom volume property:

Objective-C

prop = [POPAnimatableProperty propertyWithName:@"com.foo.radio.volume" initializer:^(POPMutableAnimatableProperty *prop) {
  // read value
  prop.readBlock = ^(id obj, CGFloat values[]) {
    values[0] = [obj volume];
  };
  // write value
  prop.writeBlock = ^(id obj, const CGFloat values[]) {
    [obj setVolume:values[0]];
  };
  // dynamics threshold
  prop.threshold = 0.01;
}];

anim.property = prop;

Swift

if let prop = POPAnimatableProperty.property(withName: "com.foo.radio.volume", initializer: { prop in
    guard let prop = prop else {
        return
    }
    // read value
    prop.readBlock = { obj, values in
        guard let obj = obj as? Volumeable, let values = values else {
            return
        }

        values[0] = obj.volume
    }
    // write value
    prop.writeBlock = { obj, values in
        guard var obj = obj as? Volumeable, let values = values else {
            return
        }

        obj.volume = values[0]
    }
    // dynamics threshold
    prop.threshold = 0.01
}) as? POPAnimatableProperty {
    anim.property = prop
}

For a complete listing of provided animatable properties, as well more information on declaring custom properties see POPAnimatableProperty.h.

Debugging

Here are a few tips when debugging. Pop obeys the Simulator's Toggle Slow Animations setting. Try enabling it to slow down animations and more easily observe interactions.

Consider naming your animations. This will allow you to more easily identify them when referencing them, either via logging or in the debugger:

Objective-C

anim.name = @"springOpen";

Swift

anim.name = "springOpen"

Each animation comes with an associated tracer. The tracer allows you to record all animation-related events, in a fast and efficient manner, allowing you to query and analyze them after animation completion. The below example starts the tracer and configures it to log all events on animation completion:

Objective-C

POPAnimationTracer *tracer = anim.tracer;
tracer.shouldLogAndResetOnCompletion = YES;
[tracer start];

Swift

if let tracer = anim.tracer {
    tracer.shouldLogAndResetOnCompletion = true
    tracer.start()
}

See POPAnimationTracer.h for more details.

Testing

Pop has extensive unit test coverage. To install test dependencies, navigate to the root pop directory and type:

pod install

Assuming CocoaPods is installed, this will include the necessary OCMock dependency to the unit test targets.

SceneKit

Due to SceneKit requiring iOS 8 and OS X 10.9, POP's SceneKit extensions aren't provided out of box. Unfortunately, weakly linked frameworks cannot be used due to issues mentioned in the Xcode 6.1 Release Notes.

To remedy this, you can easily opt-in to use SceneKit! Simply add this to the Preprocessor Macros section of your Xcode Project:

POP_USE_SCENEKIT=1

Resources

A collection of links to external resources that may prove valuable:

Contributing

See the CONTRIBUTING file for how to help out.

License

Pop is released under a BSD License. See LICENSE file for details.