What I am trying to do is a custom animation of pushing ViewController from the left side.
I have created my custom transitioning delegate and I provide my custom animation, and everything works fine (new view slides from the left side).
The only problem is that push animation in iOS isn't only about sliding a view from the right side. The VC being obscured is also slightly moving in the same directions as the VC being pushed. Also, navigation bar kinda blinks. I can of course try to imitate this behaviour by guessing what the parameters should be (for example how much the VC being obscured moves on different iPhones), but maybe it is possible to find the values somewhere?
Help greatly appreciated.
I would create a UIViewControllerAnimatedTransitioning protocol abiding object
class CustomHorizontalSlideTransition: NSObject, UIViewControllerAnimatedTransitioning {
var operation: UINavigationControllerOperation = .Push
convenience init(operation: UINavigationControllerOperation) {
self.init()
self.operation = operation
}
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.5
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let disappearingVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let appearingVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let bounds = UIScreen.mainScreen().bounds
if self.operation == .Push {
appearingVC.view.frame = CGRectOffset(bounds, -bounds.size.height, 0)
containerView!.addSubview(disappearingVC.view)
containerView!.addSubview(appearingVC.view)
} else {
appearingVC.view.frame = bounds
disappearingVC.view.frame = bounds
containerView!.addSubview(appearingVC.view)
containerView!.addSubview(disappearingVC.view)
}
UIView.animateWithDuration(transitionDuration(transitionContext),
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: { () -> Void in
if self.operation == .Push {
appearingVC.view.frame = bounds
} else {
disappearingVC.view.frame = CGRectOffset(bounds, -bounds.size.width, 0)
}
}) { (complete) -> Void in
transitionContext.completeTransition(true)
}
}
}
Then in your "From" and "To" view controllers, set the navigationController's delegate to self in view ViewDidAppear
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
navigationController?.delegate = self
}
The in both view controllers, override the following to provide a transitionAnimatedTransition delegate method and return the protocol abiding instance for your animation
override func transitionAnimatedTransition(operation: UINavigationControllerOperation) -> UIViewControllerAnimatedTransitioning? {
return CustomHorizontalSlideTransition(operation: operation)
}
Related
iOS 10 added a new function for custom animated view controller transitions called
interruptibleAnimator(using:)
Lots of people appear to be using the new function, however by simply implementing their old animateTransition(using:) within the animation block of a UIViewPropertyAnimator in interruptibleAnimator(using:) (see Session 216 from 2016)
However I can't find a single example of someone actually using the interruptible animator for creating interruptible transitions. Everyone seems to support it, but no one actually uses it.
For example, I created a custom transition between two UIViewControllers using a UIPanGestureRecognizer. Both view controllers have a backgroundColor set, and a UIButton in the middle that changes the backgroundColour on touchUpInside.
Now I've implemented the animation simply as:
Setup the toViewController.view to be positioned to the
left/right (depending on the direction needed) of the
fromViewController.view
In the UIViewPropertyAnimator animation block, I slide the
toViewController.view into view, and the fromViewController.view out
of view (off screen).
Now, during transition, I want to be able to press that UIButton. However, the button press was not called. Odd, this is how the session implied things should work, I setup a custom UIView to be the view of both of my UIViewControllers as follows:
class HitTestView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view is UIButton {
print("hit button, point: \(point)")
}
return view
}
}
class ViewController: UIViewController {
let button = UIButton(type: .custom)
override func loadView() {
self.view = HitTestView(frame: UIScreen.main.bounds)
}
<...>
}
and logged out the func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? results. The UIButton is being hitTested, however, the buttons action is not called.
Has anyone gotten this working?
Am I thinking about this wrong and are interruptible transitions just to pausing/resuming a transition animation, and not for interaction?
Almost all of iOS11 uses what I believe are interruptible transitions, allowing you to, for example, pull up control centre 50% of the way and interact with it without releasing the control centre pane then sliding it back down. This is exactly what I wish to do.
Thanks in advance! Spent way to long this summer trying to get this working, or finding someone else trying to do the same.
I have published sample code and a reusable framework that demonstrates interruptible view controller animation transitions. It's called PullTransition and it makes it easy to either dismiss or pop a view controller simply by swiping downward. Please let me know if the documentation needs improvement. I hope this helps!
Here you go! A short example of an interruptible transition. Add your own animations in the addAnimation block to get things going.
class ViewController: UIViewController {
var dismissAnimation: DismissalObject?
override func viewDidLoad() {
super.viewDidLoad()
self.modalPresentationStyle = .custom
self.transitioningDelegate = self
dismissAnimation = DismissalObject(viewController: self)
}
}
extension ViewController: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return dismissAnimation
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
guard let animator = animator as? DismissalObject else { return nil }
return animator
}
}
class DismissalObject: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerInteractiveTransitioning {
fileprivate var shouldCompleteTransition = false
var panGestureRecongnizer: UIPanGestureRecognizer!
weak var viewController: UIViewController!
fileprivate var propertyAnimator: UIViewPropertyAnimator?
var startProgress: CGFloat = 0.0
var initiallyInteractive = false
var wantsInteractiveStart: Bool {
return initiallyInteractive
}
init(viewController: UIViewController) {
self.viewController = viewController
super.init()
panGestureRecongnizer = UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:)))
viewController.view.addGestureRecognizer(panGestureRecongnizer)
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 8.0 // slow animation for debugging
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {}
func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
let animator = interruptibleAnimator(using: transitionContext)
if transitionContext.isInteractive {
animator.pauseAnimation()
} else {
animator.startAnimation()
}
}
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
// as per documentation, we need to return existing animator
// for ongoing transition
if let propertyAnimator = propertyAnimator {
return propertyAnimator
}
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to)
else { fatalError("fromVC or toVC not found") }
let containerView = transitionContext.containerView
// Do prep work for animations
let duration = transitionDuration(using: transitionContext)
let timingParameters = UICubicTimingParameters(animationCurve: .easeOut)
let animator = UIViewPropertyAnimator(duration: duration, timingParameters: timingParameters)
animator.addAnimations {
// animations
}
animator.addCompletion { [weak self] (position) in
let didComplete = position == .end
if !didComplete {
// transition was cancelled
}
transitionContext.completeTransition(didComplete)
self?.startProgress = 0
self?.propertyAnimator = nil
self?.initiallyInteractive = false
}
self.propertyAnimator = animator
return animator
}
#objc func handleGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
switch gestureRecognizer.state {
case .began:
initiallyInteractive = true
if !viewController.isBeingDismissed {
viewController.dismiss(animated: true, completion: nil)
} else {
propertyAnimator?.pauseAnimation()
propertyAnimator?.isReversed = false
startProgress = propertyAnimator?.fractionComplete ?? 0.0
}
break
case .changed:
let translation = gestureRecognizer.translation(in: nil)
var progress: CGFloat = translation.y / UIScreen.main.bounds.height
progress = CGFloat(fminf(fmaxf(Float(progress), -1.0), 1.0))
let velocity = gestureRecognizer.velocity(in: nil)
shouldCompleteTransition = progress > 0.3 || velocity.y > 450
propertyAnimator?.fractionComplete = progress + startProgress
break
case .ended:
if shouldCompleteTransition {
propertyAnimator?.startAnimation()
} else {
propertyAnimator?.isReversed = true
propertyAnimator?.startAnimation()
}
break
case .cancelled:
propertyAnimator?.isReversed = true
propertyAnimator?.startAnimation()
break
default:
break
}
}
}
I've a strange issue with the NavigationBar behind the Statusbar.
It only occurs when the default statusbar changes to an "active" statusbar like the one that appears during an active call or a wifi hotspot.
Before the "active" statusbar appears, it looks like this (which is perfectly fine):
When I enable the wifi hotspot it's still fine:
But when I disable the wifi hotspot or end a call the statusbar size shrinks back to its previous size but the ViewController (in this case a UITableViewController) doesn't move up again. It looks like it has a top margin of the statusbars' size. In addition the statusbar is transparent and I can see the background of the view controller below the actual table view controller.
Any ideas on this issue?
Update:
I figured out that it's because of a custom modal transition that I've implemented.
It should be a dissolve animation.
That's the code:
class DissolveTransition: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
// vars
private var duration: NSTimeInterval = 0.3
private var presenting = true
// MARK: - UIViewControllerAnimatedTransitioning
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return self.duration
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let destination = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
if (destination?.isBeingPresented() == true) {
self.animatePresentation(transitionContext)
}
else {
self.animateDismissal(transitionContext)
}
}
private func animatePresentation(transitionContext: UIViewControllerContextTransitioning) {
self.animateDissolve(transitionContext)
}
private func animateDismissal(transitionContext: UIViewControllerContextTransitioning) {
self.presenting = false
self.animateDissolve(transitionContext)
}
private func animateDissolve(transitionContext: UIViewControllerContextTransitioning) {
let source = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let destination = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let container = transitionContext.containerView()!
destination.beginAppearanceTransition(true, animated: true)
let snapshotFromView = source.view.snapshotViewAfterScreenUpdates(true)
// 1. adding real view at the bottom of the view hierarchy
if (self.presenting) {
container.addSubview(destination.view)
}
// 2. adding snapshot of previous view to view hierarchy
container.addSubview(snapshotFromView)
// 3. removing (fade) prev snapshot view and show real VC
UIView.animateWithDuration(self.duration, animations: {
snapshotFromView.alpha = 0.0
}, completion: { (finished) in
if (finished) {
snapshotFromView.removeFromSuperview()
container.bringSubviewToFront(destination.view)
}
transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
destination.endAppearanceTransition()
})
}
// MARK: - UIViewControllerTransitioningDelegate
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return self
}
}
I found out that it was because of my custom modal transition that presented this view.
There is an odd bug in iOS that views inside the screen are not resized after the statusBar is changed. This also appears in many well-known Apps.
I fixed it by resizing the views when the statusbar-size changes.
Use the following code in your AppDelegate:
func application(application: UIApplication, willChangeStatusBarFrame newStatusBarFrame: CGRect) {
if (newStatusBarFrame.size.height < 40) {
if let window = self.window, subviews = self.window?.subviews {
for view in subviews {
UIView.animateWithDuration(0.3, animations: {
view.frame = window.bounds
})
}
}
}
}
I want to use interactive transitions in my app. I have two view controllers. And when user touches a button in first view controller I am presenting second view controller modally. My custom animation is working well but interactive transition is not working. I added a gesture to left edge of screen and when I pan from left edge second view controller is presenting but not interactive it is working as same as touching to button for presenting.
My class:
class MenuTransitionManager: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning {
private var interactive = false
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 2.5
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let finalFrameForVC = transitionContext.finalFrameForViewController(toViewController)
let containerView = transitionContext.containerView()
let bounds = UIScreen.mainScreen().bounds
toViewController.view.frame = CGRectOffset(finalFrameForVC, 0, bounds.size.height)
containerView!.addSubview(toViewController.view)
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .CurveLinear, animations: {
fromViewController.view.alpha = 0.5
toViewController.view.frame = finalFrameForVC
}, completion: {
finished in
transitionContext.completeTransition(true)
fromViewController.view.alpha = 1.0
})
}
func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
// if our interactive flag is true, return the transition manager object
// otherwise return nil
return self.interactive ? self : nil
}
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return self.interactive ? self : nil
}
private var enterPanGesture: UIScreenEdgePanGestureRecognizer!
var sourceViewController: UIViewController! {
didSet {
self.enterPanGesture = UIScreenEdgePanGestureRecognizer()
self.enterPanGesture.addTarget(self, action:"handleOnstagePan:")
self.enterPanGesture.edges = UIRectEdge.Left
self.sourceViewController.view.addGestureRecognizer(self.enterPanGesture)
}
}
func handleOnstagePan(pan: UIPanGestureRecognizer){
// how much distance have we panned in reference to the parent view?
let translation = pan.translationInView(pan.view!)
// do some math to translate this to a percentage based value
let d = translation.x / CGRectGetWidth(pan.view!.bounds) * 0.5
// now lets deal with different states that the gesture recognizer sends
switch (pan.state) {
case UIGestureRecognizerState.Began:
// set our interactive flag to true
self.interactive = true
// trigger the start of the transition
self.sourceViewController.performSegueWithIdentifier("showAction", sender: self)
break
case UIGestureRecognizerState.Changed:
// update progress of the transition
self.updateInteractiveTransition(d)
break
default: // .Ended, .Cancelled, .Failed ...
// return flag to false and finish the transition
self.interactive = false
self.finishInteractiveTransition()
}
}
}
My first view controller:
override func viewDidLoad() {
super.viewDidLoad()
self.transitionManager.sourceViewController = self
}
var transitionManager = MenuTransitionManager()
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return transitionManager
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAction" {
let toViewController = segue.destinationViewController as UIViewController
toViewController.transitioningDelegate = self
toViewController.modalPresentationStyle = .Custom
}
}
How can I fix it?
You also need to implement interactionControllerForPresentation(_:) on the view controller and vend an instance of UIViewControllerInteractiveTransitioning (which is a sub-protocol of UIPercentDrivenInteractiveTransition that your MenuTransitionManager class already implements).
The documentation around this subject is actually pretty good.
I have two views I would like to make a swipe style transition accross and I have done that when there is a segue to act on but the I don't have one here so am not sure how to apply my animation class. All I have in my class is:
let stb = UIStoryboard(name: "Walkthrough", bundle: nil)
let walkthrough = stb.instantiateViewControllerWithIdentifier("walk") as! BWWalkthroughViewController
self.presentViewController(walkthrough, animated: true, completion: nil)
I want to apply apply the following custom segue:
class CustomSegue: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(0.0, screenHeight, screenWidth, screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.2, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, -screenWidth, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, -screenWidth, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion:nil)
}
}
}
I cannot get it to work any pointers please?
While the first answer should be "use Storyboard Segues", you can solve custom transitions this way:
Generic Approach
Modify your CustomSegue to adopt both UIStoryboardSegue and UIViewControllerAnimatedTransitioning protocols.
Refactor CustomSegue so that the animation can be used by both protocols.
Setup a delegate to the navigation controller, which can be itself, to supply the custom transitions to push & pop
let animationControllerForOperation create and return an instance of CustomSegue, with an identifier of your choice.
Overview
// Adopt both protocols
class CustomSegue: UIStoryboardSegue, UIViewControllerAnimatedTransitioning {
func animate(firstVCView:UIView,
secondVCView:UIView,
containerView:UIView,
transitionContext: UIViewControllerContextTransitioning?) {
// factored transition code goes here
}) { (Finished) -> Void in
if let context = transitionContext {
// UIViewControllerAnimatedTransitioning
} else {
// UIStoryboardSegue
}
}
}
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
// return timing
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// Perform animate using transitionContext information
// (UIViewControllerAnimatedTransitioning)
}
override func perform() {
// Perform animate using segue (self) variables
// (UIStoryboardSegue)
}
}
Below is the complete code example. It has been tested. Notice that I also fixed a few animation bugs from the original question, and added a fade-in effect to emphasize the animation.
CustomSegue Class
// Animation for both a Segue and a Transition
class CustomSegue: UIStoryboardSegue, UIViewControllerAnimatedTransitioning {
func animate(firstVCView:UIView,
secondVCView:UIView,
containerView:UIView,
transitionContext: UIViewControllerContextTransitioning?) {
// Get the screen width and height.
let offset = secondVCView.bounds.width
// Specify the initial position of the destination view.
secondVCView.frame = CGRectOffset(secondVCView.frame, offset, 0.0)
firstVCView.superview!.addSubview(secondVCView)
secondVCView.alpha = 0;
// Animate the transition.
UIView.animateWithDuration(self.transitionDuration(transitionContext!),
animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, -offset, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, -offset, 0.0)
secondVCView.alpha = 1; // emphasis
}) { (Finished) -> Void in
if let context = transitionContext {
context.completeTransition(!context.transitionWasCancelled())
} else {
self.sourceViewController.presentViewController(
self.destinationViewController as! UIViewController,
animated: false,
completion:nil)
}
}
}
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 4 // four seconds
}
// Perform Transition (UIViewControllerAnimatedTransitioning)
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
self.animate(transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!.view,
secondVCView: transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!.view,
containerView: transitionContext.containerView(),
transitionContext: transitionContext)
}
// Perform Segue (UIStoryboardSegue)
override func perform() {
self.animate(self.sourceViewController.view!!,
secondVCView: self.destinationViewController.view!!,
containerView: self.sourceViewController.view!!.superview!,
transitionContext:nil)
}
}
Host ViewController Class
class ViewController: UIViewController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.delegate = self
}
func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
switch operation {
case .Push:
return CustomSegue(identifier: "Abc", source: fromVC, destination: toVC)
default:
return nil
}
}
}
I've been looking for swift code to make simple custom slide transitions between views (just left to right or right to left, without bounce) but I only found code for complicated animations. Thanks everyone for your help !
Oscar
I finally found the answer here : http://mathewsanders.com/animated-transitions-in-swift/#custom-transition-animations and adpated it a little bit.
1) Create this Swift NSObject file
class TransitionManager2: NSObject, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate {
private var presenting = true
// MARK: UIViewControllerAnimatedTransitioning protocol methods
// animate a change from one viewcontroller to another
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
// get reference to our fromView, toView and the container view that we should perform the transition in
let container = transitionContext.containerView()
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
// set up from 2D transforms that we'll use in the animation
let offScreenRight = CGAffineTransformMakeTranslation(container.frame.width, 0)
let offScreenLeft = CGAffineTransformMakeTranslation(-container.frame.width, 0)
// prepare the toView for the animation
toView.transform = self.presenting ? offScreenRight : offScreenLeft
// set the anchor point so that rotations happen from the top-left corner
toView.layer.anchorPoint = CGPoint(x:0, y:0)
fromView.layer.anchorPoint = CGPoint(x:0, y:0)
// updating the anchor point also moves the position to we have to move the center position to the top-left to compensate
toView.layer.position = CGPoint(x:0, y:0)
fromView.layer.position = CGPoint(x:0, y:0)
// add the both views to our view controller
container.addSubview(toView)
container.addSubview(fromView)
// get the duration of the animation
// DON'T just type '0.5s' -- the reason why won't make sense until the next post
// but for now it's important to just follow this approach
let duration = self.transitionDuration(transitionContext)
// perform the animation!
// for this example, just slid both fromView and toView to the left at the same time
// meaning fromView is pushed off the screen and toView slides into view
// we also use the block animation usingSpringWithDamping for a little bounce
UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: nil, animations: {
// slide fromView off either the left or right edge of the screen
// depending if we're presenting or dismissing this view
fromView.transform = self.presenting ? offScreenLeft : offScreenRight
toView.transform = CGAffineTransformIdentity
}, completion: { finished in
// tell our transitionContext object that we've finished animating
transitionContext.completeTransition(true)
})
}
// return how many seconds the transiton animation will take
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
return 0.4
}
// MARK: UIViewControllerTransitioningDelegate protocol methods
// return the animataor when presenting a viewcontroller
// remmeber that an animator (or animation controller) is any object that aheres to the UIViewControllerAnimatedTransitioning protocol
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// these methods are the perfect place to set our `presenting` flag to either true or false - voila!
self.presenting = true
return self
}
// return the animator used when dismissing from a viewcontroller
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.presenting = false
return self
}
}
2) Change the segue between the 2 ViewControllers to "Custom"
3) Add in the first ViewController this code :
let transitionManager = TransitionManager2()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// this gets a reference to the screen that we're about to transition to
let toViewController = segue.destinationViewController as! UIViewController
// instead of using the default transition animation, we'll ask
// the segue to use our custom TransitionManager object to manage the transition animation
toViewController.transitioningDelegate = self.transitionManager
}
What you need to do is subclass UIStoryboardSegue Class and override the perform method.
The code inside your perform method would be something like this
var ourOriginViewController = self.sourceViewController as! UIViewController
ourOriginViewController.navigationController?.pushViewController(self.destinationViewController as! UIViewController, animated: false)
var transitionView = ourOriginViewController.navigationController?.view
UIView.transitionWithView(transitionView!, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromRight, animations: { () -> Void in
}) { (success) -> Void in
}
Assign this segue class to your custom segue in storyboard
Attaching screenshot for reference