Skip to content

Instantly share code, notes, and snippets.

@marcboeren
Created March 19, 2015 20:02
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save marcboeren/165ed7de30178acfdad4 to your computer and use it in GitHub Desktop.
Save marcboeren/165ed7de30178acfdad4 to your computer and use it in GitHub Desktop.
Segue from Right (Slide the next controllers view in from right to left (and back))
import UIKit
class UIStoryboardSegueFromRight: UIStoryboardSegue {
override func perform()
{
let src = self.sourceViewController as UIViewController
let dst = self.destinationViewController as UIViewController
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransformMakeTranslation(src.view.frame.size.width, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
dst.view.transform = CGAffineTransformMakeTranslation(0, 0)
},
completion: { finished in
src.presentViewController(dst, animated: false, completion: nil)
}
)
}
}
class UIStoryboardUnwindSegueFromRight: UIStoryboardSegue {
override func perform()
{
let src = self.sourceViewController as UIViewController
let dst = self.destinationViewController as UIViewController
src.view.superview?.insertSubview(dst.view, belowSubview: src.view)
src.view.transform = CGAffineTransformMakeTranslation(0, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
src.view.transform = CGAffineTransformMakeTranslation(src.view.frame.size.width, 0)
},
completion: { finished in
src.dismissViewControllerAnimated(false, completion: nil)
}
)
}
}

Assign the class UIStoryboardSegueFromRight to the custom segue in the storyboard.

To create an Unwind Segue, you'll need the code below in the first controller. You'll use the segueToMe to connect to the Exit in the second controller. Give that Unwind segue the identifier e.g. "returnToMainViewController".

@IBAction func segueToMe(segue: UIStoryboardSegue) {
// segue back
}
override func segueForUnwindingToViewController(toViewController: UIViewController, fromViewController: UIViewController, identifier: String?) -> UIStoryboardSegue {
if let id = identifier {
if id == "returnToMainViewController" {
let unwindSegue = UIStoryboardUnwindSegueFromRight(identifier: id, source: fromViewController, destination: toViewController)
return unwindSegue
}
}
return super.segueForUnwindingToViewController(toViewController, fromViewController: fromViewController, identifier: identifier)
}
@neodave
Copy link

neodave commented Oct 24, 2018

Here is the code updated to Swift 4.2

This goes in a separate UIStoryboardSegueExtensions swift file

import UIKit

class UIStoryboardSegueFromRight: UIStoryboardSegue {

override func perform()
{
    let src = self.source as UIViewController
    let dst = self.destination as UIViewController
    
    src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
    dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)
    
    UIView.animate(withDuration: 0.25,
                               delay: 0.0,
                               options: [.curveEaseIn, .curveEaseOut],
                               animations: {
                                dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
    },
                               completion: { finished in
                                src.present(dst, animated: false, completion: nil)
    }
    )
}

}

class UIStoryboardUnwindSegueFromRight: UIStoryboardSegue {

override func perform()
{
    let src = self.source as UIViewController
    let dst = self.destination as UIViewController
    
    src.view.superview?.insertSubview(dst.view, belowSubview: src.view)
    src.view.transform = CGAffineTransform(translationX: 0, y: 0)
    
    UIView.animate(withDuration: 0.25,
                               delay: 0.0,
                               options: [.curveEaseIn, .curveEaseOut],
                               animations: {
                                src.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)
    },
                               completion: { finished in
                                src.dismiss(animated: false, completion: nil)
    }
    )
}

}

And this is the revised code for your source view controller

override func segueForUnwinding(to toViewController: UIViewController, from fromViewController: UIViewController, identifier: String?) -> UIStoryboardSegue {

    if let id = identifier {
        if id == "returnToMainViewController" {
            let unwindSegue = UIStoryboardUnwindSegueFromRight(identifier: id, source: fromViewController, destination: toViewController)
            return unwindSegue
        }
    }
    
    return super.segueForUnwinding(to: toViewController, from: fromViewController, identifier: identifier)!
}

@IBAction func segueToMe(segue: UIStoryboardSegue) {
    let controller = segue.source as! ##SecondViewController##
} 

Tested and works

@matthijsotterloo
Copy link

This keeps crashing for me on the UIStoryboardSegueFromRight function.

completion: { finished in
                                src.present(dst, animated: false, completion: nil)
    }

Sometimes it works and sometimes it crashes with an unspecific error.

@lok225
Copy link

lok225 commented Mar 19, 2019

This keeps crashing for me on the UIStoryboardSegueFromRight function.

completion: { finished in
                                src.present(dst, animated: false, completion: nil)
    }

Sometimes it works and sometimes it crashes with an unspecific error.

The same happens for me. What did you end up doing matt?

@frameworker2019
Copy link

Seems not a solution anymore in 2023:

iOS15, > Swift 5.5, code always crashes on the src.present command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment