Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to present view controller from left to right in iOS?

When adding a new controller to the navigation stack:

self.navigationController!.pushViewController(PushedViewController(), animated: true)

it appears from the right:

enter image description here

How can I change the direction of animation to make it appear from the left?

like image 821
Max Avatar asked Aug 03 '18 14:08

Max


People also ask

How do I go back to the previous view controller in iOS 4?

Open your storyboard where your different viewController are located. Tap the viewController you would like your navigation controller to start from. On the top of Xcode, tap "Editor" -> Tap embed in.


6 Answers

Swift 5.1: Segue from different directions

Here is a simple extension for different segue directions. (Tested in Swift 5)

It looks like you want to use segueFromLeft() I added some other examples as well.

extension CATransition {

//New viewController will appear from bottom of screen.
func segueFromBottom() -> CATransition {
    self.duration = 0.375 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromTop
    return self
}
//New viewController will appear from top of screen.
func segueFromTop() -> CATransition {
    self.duration = 0.375 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromBottom
    return self
}
 //New viewController will appear from left side of screen.
func segueFromLeft() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.moveIn
    self.subtype = CATransitionSubtype.fromLeft
    return self
}
//New viewController will pop from right side of screen.
func popFromRight() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.reveal
    self.subtype = CATransitionSubtype.fromRight
    return self
}
//New viewController will appear from left side of screen.
func popFromLeft() -> CATransition {
    self.duration = 0.1 //set the duration to whatever you'd like.
    self.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    self.type = CATransitionType.reveal
    self.subtype = CATransitionSubtype.fromLeft
    return self
   }
}

And here is how you implement the above extension:

    let nav = self.navigationController //grab an instance of the current navigationController
    DispatchQueue.main.async { //make sure all UI updates are on the main thread.
        nav?.view.layer.add(CATransition().segueFromLeft(), forKey: nil)
        nav?.pushViewController(YourViewController(), animated: false)
    }
like image 69
A. Welch Avatar answered Oct 10 '22 16:10

A. Welch


let obj = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")as! ViewController
            
let transition:CATransition = CATransition()
transition.duration = 0.3
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
transition.type = .push
transition.subtype = .fromLeft
self.navigationController?.view.layer.add(transition, forKey: kCATransition)

self.navigationController?.pushViewController(obj, animated: true)

Whene you use popToViewController that Time

 transition.subtype = kCATransitionFromRight
like image 34
Tm Goyani Avatar answered Oct 10 '22 15:10

Tm Goyani


Ok, here's a drop-in solution for you. Add file named LeftToRightTransitionProxy.swift with the next content

import UIKit

final class LeftToRightTransitionProxy: NSObject {

    func setup(with controller: UINavigationController) {
        controller.delegate = self
    }
}

extension LeftToRightTransitionProxy: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == .push {
            return AnimationController(direction: .forward)
        } else {
            return AnimationController(direction: .backward)
        }
    }
}

private final class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    enum Direction {
        case forward, backward
    }

    let direction: Direction

    init(direction: Direction) {
        self.direction = direction
    }

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.3
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to),
            let fromView = transitionContext.view(forKey: .from) else {
                return
        }

        let container = transitionContext.containerView
        container.addSubview(toView)

        let initialX: CGFloat
        switch direction {
        case .forward: initialX = -fromView.bounds.width
        case .backward: initialX = fromView.bounds.width
        }
        toView.frame = CGRect(origin: CGPoint(x: initialX, y: 0), size: toView.bounds.size)

        let animation: () -> Void = {
            toView.frame = CGRect(origin: .zero, size: toView.bounds.size)
        }
        let completion: (Bool) -> Void = { _ in
            let success = !transitionContext.transitionWasCancelled
            if !success {
                toView.removeFromSuperview()
            }
            transitionContext.completeTransition(success)
        }
        UIView.animate(
            withDuration: transitionDuration(using: transitionContext),
            animations: animation,
            completion: completion
        )
    }
}

And here's how you can use it:

final class ViewController: UIViewController {

    let animationProxy = LeftToRightTransitionProxy()

    override func viewDidLoad() {
        super.viewDidLoad()

        animationProxy.setup(with: navigationController!)
    }
}

This solution provides animation for both forward and backward (push and pop) directions. This can be controlled in navigationController(_:animationControllerFor:from:to:) method of your LeftToRightTransitionProxy class (just return nil to remove animation).

If you need this behaviour for specific subclass of UIViewController put appropriate checks in navigationController(_:animationControllerFor:from:to:) method:

func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    if operation == .push && toVC is DetailViewController {
        return AnimationController(direction: .forward)
    } else if operation == .pop && toVC is ViewController {
        return AnimationController(direction: .backward)
    }
    return nil
}
like image 44
rkyr Avatar answered Oct 10 '22 15:10

rkyr


This may help you

let nextVc  = self.storyboard?.instantiateViewController(withIdentifier: "nextVc")
    let transition = CATransition()
    transition.duration = 0.5
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromLeft
    transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
    view.window!.layer.add(transition, forKey: kCATransition)
    self.navigationController?.pushViewController(nextVc!, animated: false)
like image 31
Naga Syam Avatar answered Oct 10 '22 15:10

Naga Syam


You'll need to write your own transition procedure to achieve your needs.

DOCS from Apple:

https://developer.apple.com/documentation/uikit/uiviewcontrollercontexttransitioning

Article:

https://medium.com/@ludvigeriksson/custom-interactive-uinavigationcontroller-transition-animations-in-swift-4-a4b5e0cefb1e

like image 1
Martin Prusa Avatar answered Oct 10 '22 16:10

Martin Prusa


I used Hero as a solution.

import Hero

Then in that place where you’re going to show new UIViewController turn the default animation:

Hero.shared.defaultAnimation = HeroDefaultAnimationType.cover(direction: .right)

Also specify that your UINavigationController is going to use the Hero library:

self.navigationController?.hero.isEnabled = true

After that you’ll get the expected result even if you’re using the standard pushViewController function:

self.navigationController?.pushViewController(vc, animated: true)

enter image description here

like image 2
Max Avatar answered Oct 10 '22 15:10

Max