An experimental approach to building UIViewControllerAnimatedTransitioning transitions out of small configurable behaviour modules directly in the storyboard. A behaviour applies a single animation to a single UIView, so in this way you can compose a complex transition out of small building blocks, all in the relative comfort of IB, without any code.
Hand over the transition animation implementation to your designer, and say goodbye to hundreds of lines of convoluted UIViewControllerAnimatedTransitioning implementation code!
The project has an example implementation of multiple transitions from one UIViewController to experiment with. All the detail is in the storyboard:
- A transition is made up of many
TransitionBehaviourobjects. Each of these objects is a concrete subclass ofTransitionBehaviour, and is used to apply a specific animation behaviour to a specific view. For example, theFadeOutTransitionBehaviourobject will fade out the view it's connected to. - Configurable properties (
IBInspectableof course) for everyTransitionBehaviour:- Animation curve - standard UIView animation curves: EaseIn, EaseOut, EaseInOut, Linear
- Spring properties - using UIView animate spring velocity and damping
- Relative start and end times, for timeline based animations
- A view can have many behaviours, so you can compose a complex animation for a single
UIViewout of multipleTransitionBehaviourobjects. - Each
TransitionBehaviourbelongs to aTransitionBehaviourCollectionobject. These are used to group behaviours for a single transition. In this way, one transition uses multipleTransitionBehaviourobjects grouped by aTransitionBehaviourCollection. This collection object has atransitionIdentifier, which means you can implement multiple transitions from a single view controller. Usually you will have one of these in the source view controller and one in the destination, because you'll probably have stuff in both the source and destination you want to animate for a transition. - Finally, your source view controller will need a
BehaviourBasedTransitionobject, connected to the view controller'stransitionscollection outlet. ThisBehaviourBasedTransitionhas atransitionIdentifier(to link it with the behaviours) and asegueIdentifierto link it to the segue it should transition for.
This is still in experimental stage, so things will likely change a lot and will change quite rapidly. You've been warned!
Add this repo to your Cartfile and follow standard Carthage procedure to build and link it.
Note: Carthage support is limited. You won't be able to see the IBInspectable properties in IB because Xcode needs the actual source for the classes to be present in the project/workspace. You can work around this by simply adding the BehaviourBasedTransitions xcodeproj inside the Carthage checkouts folder to your project/workspace. Still link to the static binary framework as normal, but just have the source available to Xcode via the xcodeproj. See of the following issue for more details: Carthage/Carthage#335
Add this repo as a git submodule and then follow standard procedure to link the framework to your project.
In a lot of cases, you'll want to transition views that are created dynamically (for example, a UIImageView in a UICollectionViewCell in the UICollectionView of your UICollectionViewController). For this you can implement the TransitionBehaviourViewProvider protocol and connect to your TransitionBehaviour object. Use the viewForBehaviour(identifier:) method to implement logic to return the appropriate view for the behaviour. You can return nil, which will cause the behaviour to have no effect.
There is support for linking behaviours that are situated in different view controllers. In this way, you can have a behaviour that effects a view in the source view controller, but uses the frame or other properties of a view in the destination controller for the animation. An example of this is the TransformToPositionSourceBehaviour and TransformToPositionDestinationBehaviour, which via the behaviourIdentifier property are linked together to provide Photos.app style transitions (small image grows to full size in the new view controller). The combination of both behaviours handle snapshotting, movement, scale and view visibility for the whole transition effect.
Yes, the framework supports interactive transitions! To make your transition interactive, do the following in Interface Builder:
- Add a
UIPanGestureRecognizerto your view controller - Link the recognizer to the view it should recognize on
- Add a
VerticalPanInteractionHandlerto your view controller - Link the
delegateof the gesture recognizer to the interaction handler - Link the
actionof the gesture recognizer to the interaction handler - Link the
gestureRecognizerof the interaction handler to the gesture recognizer. - If this is a presentation transition, link up the
sourceViewControllerandtransitionoutlets to their respective objects. For a dismissal transition, link up thedestinationViewControlleroutlet.
Rejoice that you didn't have to write a single line of code to add interactivity to your transition!
To implement new TransitionBehaviours, simply subclass the TransitionBehaviour object and extend the 3 callback functions:
setupis used to prepare your view for animation (.alpha = 0it before fading in for example)addAnimationsis used to implement the actual animation. Use theaddAnimationfunction if want regular handling of the animation's start/duration, relative to theIBInspectablestart/duration settings for free. Otherwise, feel free to do anything you want here that is animation related, as long as it's finished by the end of thetransitionDurationcompleteis used for clean up, to reset your views to an expected state
And don't forget to submit a PR with your fancy new behaviour ;)
To implement new InteractionHandlers, simply subclass the InteractionHandlers object and extend the 4 callback functions:
setupForGestureBeginis used to prepare your handler when the gesture is recognized. Can be useful for using the touch location to set a limit for percent calculation for example.calculatePercentis where you calculate how far along the transition is, depending on values from theUIGestureRecognizerclass you're handling. For example, the touch location relative to the top of the screen for a vertical pan interaction.shouldBeginPresentationTransitionreturntrueif the gesture state is correct for a presentation transition. For example, negative y velocity for a pan up.shouldBeginDismissalTransitionreturntrueif the gesture state is correct for a dismissal transition. For example, positive y velocity for a pan down.
Don't forget to submit a PR! ;)
- Add more
TransitionBehaviours (blur, 3D stuff, opacity), and expand the existing ones to allow physics based UIView animations configurable via IBInspectables - Add more
InteractionHandlers (pinch, swipe, 3D touch) - Add tests
- Add Cocoapods, Swift Package Manager support