Custom View Controller Transitions - sammanthp007/Linux-Kernel-Development GitHub Wiki
By default, modal transitions can only be one of a few stock transitions. As of iOS 7, its easy to create custom, interactive transitions. These transitions can also be used to customize navigation and tab bar controller transitions.
Step 1: Setting up the Transition
Create a modal transition in the Storyboard, as usual. Before a segue occurs, the framework will call a method called prepareForSegue
in the source view controller. You'll have to override that method and specify that you want a custom transition.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
var destinationVC = segue.destinationViewController as UIViewController
destinationVC.modalPresentationStyle = UIModalPresentationStyle.Custom
destinationVC.transitioningDelegate = self
}
The example above assumes that you only have one segue originating from the view controller. If you have multiple segues, then you'll have to check the segue identifier so you can configure the correct transition.
Step 2: Implementing the Transitioning Delegate methods
Declare the UIViewControllerTransitioningDelegate
and UIViewControllerAnimatedTransitioning
protocols in the class definition. Its also convenient to add a property to track whether the view controller is being presented or dismissed.
class MyViewController: UIViewController, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
var isPresenting: Bool = true
...
}
Implement the transition delegate methods.
func animationControllerForPresentedController(presented: UIViewController!, presentingController presenting: UIViewController!, sourceController source: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
isPresenting = true
return self
}
func animationControllerForDismissedController(dismissed: UIViewController!) -> UIViewControllerAnimatedTransitioning! {
isPresenting = false
return self
}
Finally, implement the method that actually controls the transition.
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
// The value here should be the duration of the animations scheduled in the animationTransition method
return 0.4
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// TODO: animate the transition in Step 3 below
}
Step 3: Animate the transition
The final step is to implement the animateTransition method above which controls the custom transition. In animateTransition, you have access to a containerView which will contain the views of both the source and destination view controller. You also have access to the source and destination view controller.
In order to animate the transition, you generally have to add the view of the destination view controller to the container view and schedule the desired animations. In the completion block of the animation, it's important to call completeTransition
on the transitionContext to return it to a consistent state.
For example, to fade the view controller, do the following:
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
println("animating transition")
var containerView = transitionContext.containerView()
var toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
var fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
if (isPresenting) {
containerView.addSubview(toViewController.view)
toViewController.view.alpha = 0
UIView.animateWithDuration(0.4, animations: { () -> Void in
toViewController.view.alpha = 1
}) { (finished: Bool) -> Void in
transitionContext.completeTransition(true)
}
} else {
UIView.animateWithDuration(0.4, animations: { () -> Void in
fromViewController.view.alpha = 0
}) { (finished: Bool) -> Void in
transitionContext.completeTransition(true)
fromViewController.view.removeFromSuperview()
}
}
}
Interactive Transitions
Interactive transitions are a great way to add control to the transition. For example a person could pinch in and out revealing and hiding the next screen as they pinch.
Step 1: Setup
You should have followed the steps above, now you just need to a variable interactiveTransition
as a class variable. You can see it below:
class MyViewController: UIViewController, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
var isPresenting: Bool = true
var interactiveTransition: UIPercentDrivenInteractiveTransition!
...
}
Step 2: Adding your interaction controller delegate method
When you cmd + click UIViewControllerTransitioningDelegate
you should see this function interactionControllerForPresentation
. Add this to your ViewController file and initialize the interactive transition.
func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
interactiveTransition = UIPercentDrivenInteractiveTransition()
//Setting the completion speed gets rid of a weird bounce effect bug when transitions complete
interactiveTransition.completionSpeed = 0.99
return interactiveTransition
}
Step 3: Add your gesture code
This will make your interaction transition interactive based on the user's actions. Here we are using a pinchGestureRecognizer. You can use other gestures too.
func onPinch(sender: UIPinchGestureRecognizer) {
var scale = sender.scale
var velocity = sender.velocity
if (sender.state == UIGestureRecognizerState.Began){
//blueSegue is the name we gave our modal segue, this also starts our interactive transition
performSegueWithIdentifier("blueSegue", sender: self)
} else if (sender.state == UIGestureRecognizerState.Changed){
//We are dividing by 7 here since updateInteractiveTransition expects a number between 0 and 1
interactiveTransition.updateInteractiveTransition(scale / 7)
} else if sender.state == UIGestureRecognizerState.Ended {
if velocity > 0 {
interactiveTransition.finishInteractiveTransition()
} else {
interactiveTransition.cancelInteractiveTransition()
}
}
}