Skip to content
This repository was archived by the owner on Jan 14, 2018. It is now read-only.

Custom Transitions Guide

Mike Enriquez edited this page Dec 4, 2013 · 2 revisions

The custom transition API in ECSlidingViewController is inspired by the custom transition API introduced to UIKitin iOS 7. In fact, ECSlidingViewController uses some of the same protocols. There are a few slight differences, but the basic principles are the same. This guide covers how custom transitions work in ECSlidingViewController.

Transition Flow

A transition (custom or not) begins with a call to one of the following transitioning methods:

  • anchorTopViewToRightAnimated:
  • anchorTopViewToRightAnimated:onComplete:
  • anchorTopViewToLeftAnimated:
  • anchorTopViewToLeftAnimated:onComplete:
  • resetTopViewAnimated:
  • resetTopViewAnimated:onComplete

Before the transition occurs, these methods will first check the sliding view controller's delegate for objects to handle the animation or interaction. Depending on what is returned from the delegate, the resulting three types of transitions can occur: default, custom animation, or custom animation with a custom interaction.

Default

The default transition occurs when the delegate method slidingViewController:animationControllerForOperation:topViewController is not implemented or returns nil.

The transition uses ECSlidingAnimationController for the default animation controller and ECSlidingInteractiveTransition for the default interaction controller.

Custom Animation

A custom animation transition occurs when the delegate method slidingViewController:animationControllerForOperation:topViewController returns an animation controller and slidingViewController:interactionControllerForAnimationController: returns nil.

The returned animation controller's animateTransition: method is then called to run the transition.

This type of custom transition can still use the default interaction by making use of the sliding view controller's panGesture.

Custom Animation with Custom Interaction

A custom animation transition occurs when the delegate method slidingViewController:animationControllerForOperation:topViewController returns an animation controller and slidingViewController:interactionControllerForAnimationController: returns an interaction controller.

The returned interaction controller's startInteractiveTransition: is called to run the transition.

A couple things to note here:

  • Both delegate methods must return an object for this type of transition to occur. It is possible to return an instance of ECSlidingAnimationController for the animation controller if you wanted to use the default animation with a custom interaction.
  • The animation controller's animateTransition: method is NOT called. It is up to the interaction controller to do so if it is needed.
  • It may be useful to conditionally return nil for the interaction controller. This will cause the transition to call animateTransition: on the animation controller.

UIViewControllerAnimatedTransitioning protocol

The animation controller returned from slidingViewController:animationControllerForOperation:topViewController is expected to conform to this protocol. It contains these two methods:

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

transitionDuration: is straight forward and is expected to return the duration of the animation. You are expected to follow a couple rules when implementing animateTransition:. Note that this is the same protocol that UIKit uses from custom transition so the same rules apply here.

Rules for animateTransition:

  • You are responsible for adding subviews to the container view.
  • The passed in transitionContext object must receive a call to completeTransition: when the animation is done.
  • The start and end frames for the views involved in the transition must obey the frames returned from the transitionContext. If your animation requires a special starting/ending frame, then you have to customize the layout (see Customization in the Layout Guide).
  • For custom animation transitions that support any kind of interaction, the transitionContext's transitionWasCancelled should be taken into account. Cancelled transitions must set the frames back to the initial frames as reported by the transitionContext. Otherwise, the frames should be set to the final frames.
  • If finalFrameForViewController: returns CGRectZero, then the view should be removed at the end of the transition.
  • If initialFrameForViewController: returns CGRectZero, then the view should be added at the beginning of the transition.
  • Clean up after yourself. Be sure to remove any temporary views or snapshots that are no longer needed.

The start and end states are well defined by the transitionContext, you are free to do whatever in between as long as the rules above are followed.

UIViewControllerInteractiveTransitioning protocol

The interaction controller returned from slidingViewController:interactionControllerForAnimationController: is expected to conform to this protocol. You are required to implement this method:

- (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

This is the same protocol that UIKit uses for custom transitions, so the same rules apply for implementing this method.

Rules for startInteractiveTransition:

  • The transitionContext should be continuously updated with the percentage of completion for the interaction by calling updateInteractiveTransition:.
  • The transitionContext must be notified if the interaction was cancelled or finished by calling cancelInteractiveTransition or finishInteractiveTransition.
  • The rules for animateTransition: apply here as well.

Percent Driven

A percent driven interaction controller can control the animation controller's timeline. 0% represents the start of the animation and 100% represents the end of the animation.

Percent driven interaction controllers are implemented by subclassing ECPercentDrivenInteractiveTransition. This class conforms to the UIViewControllerInteractiveTransitioning protocol. Your subclass is expected to follow the rules, but instead of calling the transitionContext directly, you are to call the convenience methods from the superclass.

Note: Even though UIPercentDrivenInteractiveTransition conforms to the UIViewControllerInteractiveTransitioning protocol, it does not work because it calls methods on the transitionContext that don't exist in the UIViewControllerContextTransitioning protocol. Therefore, it is not compatible with ECSlidingViewController.

Using a Gesture Recognizer

Most interaction controllers will use some kind of gesture recognizer to trigger and update a transition. The gesture recognizing code will typically be a part of the interaction controller. The sequence of events in the interaction controller with a gesture is as follows:

  1. Gesture is recognized and goes into the UIGestureRecognizerStateBegan state.
  2. The "gesture began" state calls one of the transitioning methods on the sliding view controller to trigger a transition.
  3. startInteractiveTransition: gets called because a transition was triggered. Some state is setup to begin the transition here.
  4. The gesture moves to the UIGestureRecognizerStateChanged state. The "gesture changed" state can now call updateInteractiveTransition: on the transitionContext. It can do this while inspecting the state that was setup in startInteractiveTransition:.
  5. When the user ends the gesture or if it gets cancelled, the gesture recognizer can complete the transition however it sees fit. The transition could end with a UIView animation or it could end using UIKit Dynamics for a physics based finish. Anything can be done to end a transition as long as the rules are followed for startInteractiveTransition:.

It may be unintuitive to go from "gesture began" -> startInteractiveTransition: -> "gesture changed". Just remember when the transition is triggered in "gesture began", startInteractiveTransition: is called immediately as a result of that.

Clone this wiki locally