Creating a Sliding Segue in Swift

Slide Segue in Swift

I test with the following modification, and it work well.

func valForDirection() -> Int {
return direction == Direction.Left ? 1 : -1
}

If sliding to left, the destView's originX should be it's width. else -width.

Creating a sliding segue in Swift

That effect is achieved using custom interactive transitions, which were introduced in iOS7. Here are a few tutorials to check out:

  • See Custom Transitions Using View Controllers. https://developer.apple.com/videos/wwdc/2013/
  • http://www.thinkandbuild.it/ios7-custom-transitions/
  • http://objectivetoast.com/2014/04/14/interactive-transitions/
  • http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions/
  • This one gives many examples of the effects that can be achieved. http://www.appcoda.com/custom-view-controller-transitions-tutorial/

When I was implementing this I found that, for reusability, it was best to have one subclass of UIPercentDrivenInteractiveTransition (which we'll call TransitionManager) that implemented the protocols UIViewControllerTransitioningDelegate, UINavigationControllerDelegate and UIViewControllerAnimatedTransitioning.

- Then, if you need to present a UIViewController modally with your custom transition: in prepareForSegue set:

destinationViewController.modalPresentationStyle = .Custom
destinationViewController.transitioningDelegate = TransitionManager()

- If you're using a UINavigationController it's even easier, all you need to do it set the UINavigationController's delegate to your TransitionManager.

Hopefully that should start to make some sense once you've gone through the tutorials.

Slide Segue in Swift

I test with the following modification, and it work well.

func valForDirection() -> Int {
return direction == Direction.Left ? 1 : -1
}

If sliding to left, the destView's originX should be it's width. else -width.

iOS Segue - Left to Right -

This is how I achieve the effect without requiring a nav-controller. Try this instead:

Swift 4:

import UIKit
class SegueFromLeft: UIStoryboardSegue {
override func perform() {
let src = self.source
let dst = self.destination

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: .curveEaseInOut,
animations: {
dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
},
completion: { finished in
src.present(dst, animated: false, completion: nil)
}
)
}
}

Swift 3:

import UIKit

class SegueFromLeft: UIStoryboardSegue
{
override func perform()
{
let src = self.sourceViewController
let dst = self.destinationViewController

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)
}
)
}
}

Then in the storyboard, click on the segue you'd like to change. In the attributes inspector change the type to 'Custom' and change the class to 'SegueFromLeft'

Create sliding animation in View Swift

To create this segue, you will need to create a UIStoryBoardSegue file.
In that file, put this code:

 override func perform() {
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)
firstVCView.frame = CGRectMake(0.0, 0.0, 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.4, animations: { () -> Void in

firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, screenHeight)
secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, screenHeight)

}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion: nil)
}
}

Control click to create a segue. Select 'custom'. Then, type in the segue file name in the attributes inspector. Your custom segue is good to go!

Hope this helped.

Create a sliding animation with Swift

The easiest (built-in) thing that does what you want is a UIPageViewController. This will automatically do the gesture correctly (so it's like springboard).

Transition Screens from Left to Right?

You could write a custom transition that would not be too difficult but if you don't want to go that route here is a simple fix that will work. Click on the segue and unclick/disable animates on the segue. Then in prepareForSegue use this.

  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let _ = segue.destination as? NextViewController{
let trans = CATransition()
trans.type = kCATransitionMoveIn
trans.subtype = kCATransitionFromLeft
trans.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
trans.duration = 0.35
self.navigationController?.view.layer.add(trans, forKey: nil)
}
}

Feel free to explore the other options with CATransition types. You can have some serious fun with them. Now I am guessing you want to have the reverse for the back button press in the next view controllers. You will have to replace the back button and to intercept the back press and pop without animation so you can add your own animation. Here is what that would look like.

 override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(backTapped))
}

@objc func backTapped() {
let trans = CATransition()
trans.type = kCATransitionMoveIn
trans.subtype = kCATransitionFromRight
trans.duration = 0.3
self.navigationController?.view.layer.add(trans, forKey: nil)
navigationController?.popViewController(animated: false)
}

Again the other option would be use UIViewControllerAnimatedTransitioning but depending on your skill level and comfort with animations I find the above an easy implementation.



Related Topics



Leave a reply



Submit