Swiftpack.co - Package - HeroTransitions/Hero

Hero is a library for building iOS view controller transitions. It provides a declarative layer on top of the UIKit's cumbersome transition APIs—making custom transitions an easy task for developers.

Carthage compatible Accio supported codecov Version License Xcode 9.0+ iOS 8.0+ Swift 4.0+ 中文 README Donate


Hero is similar to Keynote's Magic Move. It checks the heroID property on all source and destination views. Every matched view pair is then automatically transitioned from its old state to its new state.

Hero can also construct animations for unmatched views. It is easy to define these animations via the heroModifiers property. Hero will run these animations alongside the Magic Move animations. All of these animations can be interactively controlled by user gestures.

At view controller level, Hero provides several template transitions that you can set through heroModalAnimationType, heroNavigationAnimationType, and heroTabBarAnimationType. These can be used as the foundation of your custom transitions. Combine with heroID & heroModifiers to make your own unique transitions.


By default, Hero provides dynamic duration based on the Material Design Motion Guide. Duration is automatically determined by changes to distance and size—saving you the hassle, while providing consistent and delightful animations.

Hero doesn't make any assumptions about how the view is built or structured. It won't modify any of your views' states other than hiding them during the animation. This makes it work with Auto Layout, programmatic layout, UICollectionView (without modifying its layout object), UITableView, UINavigationController, UITabBarController, etc...

Example Gallery

Checkout the Example Gallery Blog Post for a general idea of what you can achieve with Hero

Usage Example 1

View Controller 1

redView.hero.id = "ironMan"
blackView.hero.id = "batMan"

View Controller 2

self.hero.isEnabled = true
redView.hero.id = "ironMan"
blackView.hero.id = "batMan"
whiteView.hero.modifiers = [.translate(y:100)]

Usage Example 2

View Controller 1

greyView.hero.id = "skyWalker"

View Controller 2

self.hero.isEnabled = true
greyView.hero.id = "skyWalker"

// collectionView is the parent view of all red cells
collectionView.hero.modifiers = [.cascade]
for cell in redCells {
    cell.hero.modifiers = [.fade, .scale(0.5)]

You can do these in the storyboard too!



Add the following entry to your Podfile:

pod 'Hero'

Then run pod install.

Don't forget to import Hero in every file you'd like to use Hero.


Add the following entry to your Cartfile:

github "HeroTransitions/Hero"

Then run carthage update.

If this is your first time using Carthage in the project, you'll need to go through some additional steps as explained over at Carthage.


Add the following to your Package.swift:

.package(url: "https://github.com/HeroTransitions/Hero.git", .upToNextMajor(from: "1.4.0")),

Next, add Hero to your App targets dependencies like so:

    name: "App",
    dependencies: [

Then run accio update.

Swift Package Manager

To integrate using Apple's Swift package manager, add the following as a dependency to your Package.swift:

.package(url: "https://github.com/HeroTransitions/Hero.git", .upToNextMajor(from: "1.3.0"))

and then specify "Hero" as a dependency of the Target in which you wish to use Hero. Here's an example PackageDescription:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "MyPackage",
    products: [
            name: "MyPackage",
            targets: ["MyPackage"]),
    dependencies: [
        .package(url: "https://github.com/HeroTransitions/Hero.git", .upToNextMajor(from: "1.5.0"))
    targets: [
            name: "MyPackage",
            dependencies: ["Hero"])


  • Drag the Sources folder anywhere in your project.


Checkout the WIKI PAGES (Usage Guide) for documentations.

For more up-to-date ones, please see the header-doc. (use alt+click in Xcode)

Interactive Transition Tutorials

Interactive transitions with Hero (Part 1)


Not able to use Hero transition even when self.hero.isEnabled is set to true

Make sure that you have also enabled self.hero.isEnabled on the navigation controller if you are doing a push/pop inside the navigation controller.

Views being covered by another matched view during the transition

Matched views use global coordinate space while unmatched views use local coordinate space by default. Local coordinate spaced views might be covered by other global coordinate spaced views. To solve this, use the useGlobalCoordinateSpace modifier on the views being covered. Checkout Coordinate Space Wiki page for details.

Push animation is shown along side my custom animation

This is the default animation for navigation controller provided by Hero. To disable the push animation, set self.hero.navigationAnimationType to .fade or .none on the navigation controller.

How do I use a different default animation when dismissing

You can use the animation type .selectBy(presenting:dismissing) to specify a different default animation for dismiss.

For example:

    self.hero.modalAnimationType = .selectBy(presenting:.zoom, dismissing:.zoomOut)


We welcome any contributions. Please read the Contribution Guide.


Stars: 18470


Used By

Total: 0


1.5.0 - 2019-10-29 04:48:25

Maintainance Pre-Swift 5 release.

New maintainers




  • Use custom snapshot for views that implement HeroCustomSnapshotView. #541 by @ManueGE


  • Added support for right to left languages. #520 by @ManueGE

  • The hidden state of subviews are now taken into account in optimized snapshot type for UIImageView. #521 by @ManueGE


  • Fix iOS demo app failing and style on iOS 13
  • Fix lint warnings and build errors in demo app
  • Add extra metadata to podspec
  • Deprecated messages to renamed
  • Add Joe Mattiello into Podspec authors for publishing
  • Fix pod lib lint failures
  • Update Podspec imports to match source imports
  • Use more minimal import
  • Remove Swift files from framework bundle products
  • Remove access modifier warnings (#616)
  • GitIgnore xcode log files
  • Docs - Run jazzy against new spec
  • Docs - Update jazzy config
  • Bump version to 1.5.0
  • Set theme jekyll-theme-midnight
  • Use custom snapshot for views that implements HeroCustomSnapshotView (#541)
  • Keep using default navigation animation direction with RTL languages (#520)
  • Hidden subviews not taken in account in optimized snapshot type (#521)
  • Update Collection 2.0 (#553)

1.4.0 - 2018-10-14 23:15:59

This release adds support for Swift 4.2 and also maintains backward compatibility for previous Swift versions. Thank you to @rennarda for contributing to this release 🥇


1.3.1 - 2018-09-11 00:38:08

This release fixes a retain cycle caused by strong references to delegates.

Thanks to @mkieselmann for contributing to this release 👊🥇💯


  • Fixed the retain cycle caused by strong references to previousNavigationDelegate and previousTabBarDelegate. #516 by @mkieselmann

1.3.0 - 2018-07-30 18:58:12

This version fixes a few bugs related to animations and improves handling of UINavigationController delegate events and the ability to provide completion blocks for basic transition methods.

Thanks to @lkzhao, @2blane, @kartikthapar, and @bradphilips for contributing to this release 💪💯🥇


  • Adds an optional completion block parameter to the dismissViewController and replaceViewController methods. #456 by @kartikthapar


  • Allows previous UINavigationController delegate to handle delegate events. #430 by @bradphilips


  • Fixed shadows being cutoff by snapshots. #440 by @2blane
  • Fixed animation flickering on CALayer animation. f4dab9 by @lkzhao

1.2.0 - 2018-04-12 03:26:45

  • add HeroTransitionDelegate for observing transition state and progress

  • add ability to change target state during interactive transition. https://github.com/lkzhao/Hero/issues/322

    Just call the following method before calling finish(animate:) and provide the target state similar to apply(modifiers:, to:)

    Hero.shared.changeTarget(modifiers:, to:)

    for example:

    someView.hero.modifiers = [.translate(x: 100)]
    // when you want to finish interactive transition
    Hero.shared.changeTarget(modifiers:[.translate(x: -100)], to: someView)
    // this will animate someView to the state of `.translate(x: -100)` instead of `.translate(x: 100)`
  • a number of bug fixes and improvements:

    • fix 2x mode on ipad
    • Add type hinting to CascadeDirection comperator (#403) @BennX
    • Update for Xcode 9.3 and Swift 4.1 (#439) @joaomvfsantos
    • Add UIView+Hero.swift and UIViewController+Hero.swift to public heade… (#425) @DanielAsher
    • copy image view resizing filter to snapshot (#428) @sroik
    • TabBarController.selectedViewController issue (#407) @dDomovoj
    • Fix typo on 'Advanture' (#398) @fabiothiroki
    • Update README.zh-cn.md (#429) @Fidetro

API Cleanup & Bug fixes - 2018-02-07 22:33:24

  • Added Constrained extension to make API more elegant. (#367) Big thanks to @dDomovoj for making this happen!
view.heroID -> view.hero.id
view.heroModifiers -> view.hero.modifiers
// etc..
  • Make tvOS Shared to be detected by carthage (#370) Credit to: @fruitcoder
  • Prevents animation from restarting when new UITabBarController tab is pressed rapidly multiple times (#373) Credit to: @armandsLa
  • Fix debug plugin to respect iPhone X safe insets (#375) Credit to: @nick-potts
  • Fix a force unwraps crashes. (#335) @imougy
  • Fix tabbar issues with hideButtonBarOnPush
  • Internal cleanup with CG extensions (#369) @adamnemecek
  • Fix internal influencing other animations libraries.

1.0.1 - 2017-11-22 21:14:55

  • fix an issue where interactive transition happens abruptly (#299) @capt-hook
  • fix a force unwrap crash (#333) @imougy
  • fix a division by zero crash when size is zero (#313) @caihua
  • Use context's final frame for destination (#327) @zacwest
  • Changes observeForProgressUpdate protection level to public, instead of internal (#329) @mad102190
  • ability to override cornerRadius for matched view

Swift 4, Xcode 9, iOS 11 Support - 2017-10-25 22:28:47

This release fix some compatibility issue with swift 4, Xcode 9, and iOS 11.

Also looking for a maintainer!

Hero helped me learned a lot about iOS over the last year. Fighting the iOS animation system and dealing with UI bugs has been quite a journey. But I am sorry to say that I do not have to time to maintain this project anymore. The scope of this project has become unmanageable for me to handle. I am looking for a project maintainer to this project and I'm open to transfer this to a public organization instead of under my personal account.

I will still be using Hero in productions, and contribute to critical bug fixes and new iOS release.

1.0.0-alpha.4 - 2017-07-21 20:27:52

  • fix a crash when fullScreenSnapshot fails to capture. (happens when the app is backgrounded)

1.0.0-alpha.3 - 2017-07-18 22:17:11

  • fix an issue where views that are contained in a transformed view are not animated properly https://github.com/lkzhao/Hero/issues/237
  • less force-unwraps.

1.0.0-alpha.2 - 2017-07-14 19:42:51

This is the second alpha version for 1.0.0 release. Mostly bug fixes.

  • fix an issue where the duration is incorrect when resuming an animation with delay
  • fix a performance issue with interactive transition
  • remove most of the force unwrapped optional
  • fix a crash where finish/cancel is called before the animation has started.
  • make internal CAMediaTimingFunctions public
  • default container color is now black. to customize, construct your own HeroTransition object.

Example project

  • animate tabbar so that it doesnt cover the content
  • add a playground in the example project for quick tests

1.0.0-alpha.1 - 2017-06-30 20:43:48

Sorry guys for the inactivity with this project. I have been having some other commitments. From now on, I will start maintaining and updating it more often.

So to prepare for stable release 1.0, there will be a few alpha versions. I will start to clean up issues and start monitor new ones. Feel free to submit anything you have encountered while using the new versions.

New Features

  • .useNoSnapshot will now try to insert the view back to the view hierarchy once the transition completes. So you don't need to manually insert it back.

    • Note: for views that have collection view or table view as the superview, Hero might not be able to insert it into the correct subview index since the collection view and table view might have altered their subviews during the transition.
  • .useNoSnapshot will now animate subview layout changes. Very convenient when you want your custom layout be animated during the transition.

  • Added .whenXXX modifiers to make hero more declaritive.

    • instead of conforming to HeroViewControllerDelegate, you can now use .whenPresenting, .whenDismissing, .whenApearing, .whenDisapearing, .whenMatched, or your own conditions with .when
  • Added isHeroEnabledForSubviews property on UIView. Setting this to true will let Hero skip over the subview tree. This saves a lot of computation time when the subview tree is complex.

  • Better support iOS custom keyboard

  • Better support UIVisualEffectView

  • You can now create your own instance of HeroTransition instead of using isHeroEnabled & Hero.shared.

    • just create an instance of HeroTransition and assign it to the transitionDelegate property of your view controller.
  • Added viewOrderingStrategy property to HeroTransition which allow you to customize which view controller should be inserted first during the transition.

  • Added isUserInteractionEnabled property to HeroTransition which allow you to enable user interaction during the transition.

    • Note: by default, Hero will create snapshot of your views and use them for animation. They don't have the same event handler as your own views. So to enable user interaction, you have to apply .useNoSnapshot modifier to the views that you want to enabled user interaction. Also keep in mind that Hero can be in any state when you are handling user interaction. If you want to trigger a new transition, besure to call cancel(animated: false) or finish(animated: false) before starting the new transition.
  • The following methods on Hero is removed in favor of creating your custom HeroTransition object

    • func disableDefaultAnimationForNextTransition()
    • func setDefaultAnimationForNextTransition(_ animation: HeroDefaultAnimationType)
    • func setContainerColorForNextTransition(_ color: UIColor?)

Bug fixes:

  • fix the ghosting effect where the source view and target view animates at different rate
  • fix tab bar crashes and inconsistency when tapping too fast.

Future Roadmap:

  1. Custom snapshot view
  2. Masking support

Bug fixes - 2017-03-16 22:32:38

Fix #148

Bug fixes - 2017-03-15 18:29:26

  • fix a compilation bug with manual install because UIKit not imported in one file.
  • fix .selectedBy animations type not working

Better string properties parser & bug fixes - 2017-03-11 16:58:45

  • added three new string properties to set defaultAnimation

    • heroModalAnimationTypeString
    • heroNavigationAnimationTypeString
    • heroTabBarAnimationTypeString
  • new string parser that will give some error feedback

  • fix speed different bug for interaction transition #132

  • other small bug fixes.

Bug fixes - 2017-02-25 20:54:45

  • added "contentsRect" & "contentsScale" animation support
  • fix a collection view ghosting effect bug #97

0.3.2 - 2017-02-16 18:12:00

  • new properties for specifying default animations
extension UIViewController {
  /// default hero animation type for presenting & dismissing modally
  public var heroModalAnimationType: HeroDefaultAnimationType
extension UINavigationController {
  /// default hero animation type for push and pop within the navigation controller
  public var heroNavigationAnimationType: HeroDefaultAnimationType
extension UITabBarController {
  /// default hero animation type for switching tabs within the tab bar controller
  public var heroTabBarAnimationType: HeroDefaultAnimationType
  • bug fixes https://github.com/lkzhao/Hero/issues/90 https://github.com/lkzhao/Hero/issues/85
  • basic support for animating UIVisualEffectView's effect property in iOS 10

Bug fixes - 2017-02-12 19:16:35

  • fixed a view order issue #85
  • cleaned up example projects
  • general bug/regression fix for 0.3.0

OverFullScreen Support & Default Transition - 2017-02-11 02:18:41

  • support .overFullScreen modalPresentationStyle
  • Implement many new default transitions. (fade was the only default transition before this update)
    • .push(direction: Direction)
    • .pull(direction: Direction)
    • .cover(direction: Direction)
    • .uncover(direction: Direction)
    • .slide(direction: Direction)
    • .zoomSlide(direction: Direction)
    • .pageIn(direction: Direction)
    • .pageOut(direction: Direction)
  • a few new modifiers:
    • beginWith(modifiers:[HeroModifier])
    • durationMatchLongest
    • overlay(color:UIColor, opacity:CGFloat)
    • masksToBounds(_ masksToBounds: Bool)

tvOS Support - 2017-02-08 04:58:59

Shadow & Border Animation Support. New zPosition modifier behavior. - 2017-02-07 19:22:35

  • prepare for tvOS release
  • Add new zPosition modifier that animates zPosition from/to a given value. The old zPosition & zPositionIfMatched modifiers are removed. If you still want to modify the draw order, set the zPosition property on the view's layer before transition. Check the Apple HomePage Example for how to do this.
  • Add shadow and border animation modifiers:
    • shadowPath
    • shadowRadius
    • shadowOpacity
    • shadowColor
    • shadowOffset
    • borderWidth
    • borderColor

No more zPosition needed!! - 2017-02-06 21:40:12

  • fix a bug where interactive transition won't start when calling update(progress:) with progress = 0
  • Hero can now determine the draw order match more accurately! This eliminate the need for zPosition modifier to be used in most cases.

Bug fixes - 2017-02-05 05:52:31

  • fix a zPosition regression introduced in 0.1.5

Bug fixes - 2017-02-05 05:25:54

  • fix a regression introduced in 0.1.5 where animation for matched view might appear inconsistent.

Bug fixes & useScaleBasedSizeChange modifier - 2017-02-05 05:12:49


  • fix a bug where toViewController's delegate callbacks are not being called

  • fix a bug where fromViewController's delegate callbacks receive incorrect parameters.

  • Add useScaleBasedSizeChange modifier.

    Force Hero use scale based size animation. This will convert all .size modifier into .scale modifier. This is to help Hero animate layers that doesn't support bounds animation. Also gives better performance when animating.

Unwind Support & Snapshot Type Modifiers - 2017-02-05 00:05:06


  • fix a bug where changing orientation doesn't affect previous VC. https://github.com/lkzhao/Hero/issues/60
  • fix a bug where the presented view controller has incorrect frame. https://github.com/lkzhao/Hero/issues/63, https://github.com/lkzhao/Hero/issues/56
  • New snapshot type modifiers:
    • useOptimizedSnapshot

      With this modifier, Hero will create snapshot optimized for different view type when animating. For custom views or views with masking, useOptimizedSnapshot might create snapshots that appear differently than the actual view. In that case, use .useNormalSnapshot or .useSlowRenderSnapshot to disable the optimization.

    • useNormalSnapshot

      Create snapshot using snapshotView(afterScreenUpdates:).

    • useLayerRenderSnapshot

      Create snapshot using layer.render(in: currentContext). This is slower than .useNormalSnapshot but gives more accurate snapshot for some views (eg. UIStackView).

    • useNoSnapshot

      Force Hero to not create any snapshot when animating this view. Hence Hero will animate on the view directly. This will mess up the view hierarchy. Therefore, view controllers have to rebuild its view structure after the transition finishes.

  • New navigation extension on UIViewController (mainly to support unwinding):
    • func hero_dismissViewController()

      Dismiss the current view controller with animation. Will perform a navigationController.popViewController if the current view controller is contained inside a navigationController.

    • func hero_replaceViewController(with:UIViewController)

      Replace the current view controller with another VC on the navigation/modal stack.

    • func hero_unwindToRootViewController()

      Unwind to the root view controller using Hero.

    • func hero_unwindToViewController(_ toViewController:)

      Unwind to a specific view controller using Hero.

    • func hero_unwindToViewController(withSelector: Selector)

      Unwind to a view controller that responds to the given selector using Hero.

    • func hero_unwindToViewController(withClass: AnyClass)

      Unwind to a view controller with given class using Hero.

    • func hero_unwindToViewController(withMatchBlock: (UIViewController) -> Bool)

      Unwind to a view controller that the match block returns true on.

Local coordinate space support + new Apple Homepage Transition example - 2017-02-01 01:34:20

  • Support local coordinate space.

    | Global coordinate space | Local (parent's) coordinate space | | --- | --- | | Animating views are not affected by parent views' attributes | Animating views are affected by parent views' attributes | | When parent view moves, subviews that have its own modifiers do not move with the parent view. I.e. they are being taken out of the view hierarchy. | When parent view moves, subviews that have its own modifiers move along with the parent view. I.e. similar to how a view behave when its parent view moves. | | Used for matched views & views with source modifier. Global is the default prior to 0.1.3 | Local is the default coordinate space after 0.1.3 |

  • New useGlobalCoordinateSpace modifier. Force the view to use global coordinate space. I.e. won't move with its parent view.

Bug fixes - 2017-01-29 21:40:42

  • HeroPlugin returning .infinity duration will be treated as wanting interactive transition
  • few bug fixes.
  • Update plugin API protocol to be more concise.

0.1.1 - 2017-01-15 20:21:05

  • Swift Package Manager Support, Thanks to @mRs-
  • Bug fixes #41, #36, & #38
  • Cleaner navigation bar animation.
  • Better alpha animation support.

HUGE Update. Revamped Hero Modifier implementation. Bug fixes. - 2017-01-09 07:42:44

  • add HeroModifier class and HeroTargetState struct

    • HeroModifier is a swift enum-like class that provides the same functionality of the original string-based heroModifiers.
    • HeroTargetState is a struct that holds view state informations. It can be build from [HeroModifier]. Mostly used internally and for building HeroPlugin.
  • change the original heroModifiers:String? to heroModifierString:String? (breaking change!)

  • add heroModifiers:[HeroModifier]? to UIView

  • add a shared singleton Hero object for controlling the interactive transition. Which can be accessed by Hero.shared

  • few changes to the protocols

    • protocol HeroAnimator

      func temporarilySet(view:UIView, to modifiers:HeroModifiers)
      // to 
      func temporarilySet(view:UIView, targetState:HeroTargetState)
    • protocol HeroViewControllerDelegate

      @objc optional func wantInteractiveHeroTransition(context:HeroInteractiveContext) -> Bool
      // to
      @objc optional func wantInteractiveHeroTransition() -> Bool
    • remove HeroInteractiveContext protocol

  • update HeroPlugin to conform to the new protocols definitions.

  • rename a few modifiers:

    • curvetimingFunction
    • sourceIDsource
    • clearSubviewModifiersignoreSubviewModifiers
  • fix a bug with heroReplaceViewController API. PR 30

  • fix a bug with UIStackView not animating correctly. PR 22

  • add recursive ignoreSubviewModifiers modifier

  • add radial & inverseRadial cascade:

To migrate from previous versions:

Do a whole-project find & replace(cmd+option+shift+F) for:

  • heroModifiersheroModifierString

  • curvetimingFunction

  • sourceIDsource

  • clearSubviewModifiersignoreSubviewModifiers

    Remember to also replace these inside the storyboard. In code, please migrate to the new type-safe heroModifiers. It provides better type-checking and more functionality.