Latest 0.2.0
License MIT
Platforms ios 8.0, requires ARC


Usage |
Customization |


A tiny library for pushing and popping UIViews using your own custom animations. You can push and pop any views onto the stack and the framework will animate between the them by using the properties you’ve defined. You can animate between the frame, transform and alpha.


To get started you need to initialize a new PileView:

let view = PileView(frame: .zero)

Then you can push any UIView onto the stack and it will animate it into view:


To get back to the previous view, just call:



You can completly customize the animation by defining you own metrics. PileView takes four parameters for customization: the activeMetric, leadingMetric, trailingMetric and animationMetric.

When pushing a view, it will apply leadingMetric to that view and animate it to activeMetric. When popping, it will animate from activeMetric to trailingMetric. These metrics must all conform to the PileMetric protocol:

public protocol PileMetric {
  var alpha: CGFloat { get }
  var transform: CATransform3D { get }
  func frame(view: UIView, stackViewBounds: CGRect) -> CGRect

The animationMetric defines the options for the UIView animation block:

public protocol PileAnimationMetric {
  var duration: CFTimeInterval { get }
  var delay: CFTimeInterval { get }
  var damping: CGFloat { get }
  var initialVelocity: CGFloat { get }
  var options: UIViewAnimationOptions { get }


Here’s an example that flips in views horizontally to either side:

func rotationTransform(angle: Double) -> CATransform3D {
  var perspective = CATransform3DIdentity
  perspective.m34 = 1.0 / -1000
  let rotation = CATransform3DMakeRotation(CGFloat(angle), 0, 1, 0)
  return CATransform3DConcat(perspective, rotation)

struct CustomActiveMetric: PileMetric {
  let alpha: CGFloat = 1
  let transform = rotationTransform(0)

  func frame(view: UIView, stackViewBounds: CGRect) -> CGRect {
    return stackViewBounds

struct CustomLeadingMetric: PileMetric {
  let alpha: CGFloat = 0
  let transform = rotationTransform(M_PI_2)

  func frame(view: UIView, stackViewBounds: CGRect) -> CGRect {
    return stackViewBounds.offsetBy(dx: stackViewBounds.midX, dy: 0)

struct CustomTrailingMetric: PileMetric {
  let alpha: CGFloat = 0
  let transform = rotationTransform(-M_PI_2)

  func frame(view: UIView, stackViewBounds: CGRect) -> CGRect {
    return stackViewBounds.offsetBy(dx: -stackViewBounds.midX, dy: 0)

struct CustomAnimationMetric: PileAnimationMetric {
  let duration: CFTimeInterval = 1
  let delay: CFTimeInterval = 0
  let damping: CGFloat = 0.8
  let initialVelocity: CGFloat = 0
  let options = UIViewAnimationOptions.BeginFromCurrentState

Then initialize the PileView with those metrics:

let view = PileView(frame: .zero,
      activeMetric: CustomActiveMetric(),
      leadingMetric: CustomLeadingMetric(),
      trailingMetric: CustomTrailingMetric(),
      animationMetric: CustomAnimationMetric())

Download the project and run the Example target to see it in action.


Pile will be compatible with the lastest public release of Swift.


Add the following line to your Podfile and run pod install:

pod Pile', '~> 0.2.0'


Add the following to your Cartfile:

github "rechsteiner/Pile"  

Then you need to:

  1. Run carthage update
  2. Link Pile.framework with you target
  3. Add $(SRCROOT)/Carthage/Build/iOS/Pile.framework to your
    copy-frameworks script phase

See this guide for more details on using Carthage.


  • iOS 8.0+
  • Xcode 8.0+


Parchment is released under the MIT license. See LICENSE for details.

Latest podspec

    "name": "Pile",
    "version": "0.2.0",
    "license": "MIT",
    "summary": "Transition between UIViews with custom animations",
    "homepage": "",
    "authors": {
        "Martin Rechsteiner": "[email protected]"
    "social_media_url": "",
    "source": {
        "git": "",
        "tag": "v0.2.0"
    "platforms": {
        "ios": "8.0"
    "source_files": "Pile/*.swift",
    "requires_arc": true,
    "pushed_with_swift_version": "4.0"

Pin It on Pinterest

Share This