Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to present view controller from right to left in iOS using Swift

I am using presentViewController to present new screen

let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, animated: true, completion: nil)

This presents new screen from bottom to top but I want it to presented from right to left without using UINavigationController.

I am using Xib instead of storyboard so how can I do that ?

like image 569
Umair Afzal Avatar asked Jun 09 '16 09:06

Umair Afzal


People also ask

How do I present a two view controller in Swift?

For solving this, you will need to do a pretty simple trick which is to take a screenshot from the first view controller and passing it to the second view controller to display it while presenting the third view controller. You can check this repository to see how it is exactly could be done (Swift 3).

How do I present a controller in Swift?

To present a ViewController in a NavigationController you can wrap ViewController into a NavigationController as it is in the example below. Then present NavigationController which contains ViewController. Check out the below video courses to learn more about Mobile App Development for iOS platform with Swift.

How do I present a view controller from another view controller?

Start a segue from any object that implements an action method, such as a control or gesture recognizer. You may also start segues from table rows and collection view cells. Right-click the control or object in your current view controller. Drag the cursor to the view controller you want to present.


3 Answers

It doesn't matter if it is xib or storyboard that you are using. Normally, the right to left transition is used when you push a view controller into presentor's UINavigiationController.

UPDATE

Added timing function kCAMediaTimingFunctionEaseInEaseOut

Sample project with Swift 4 implementation added to GitHub


Swift 3 & 4.2

let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
transition.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.easeInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
present(dashboardWorkout, animated: false, completion: nil)


ObjC

CATransition *transition = [[CATransition alloc] init];
transition.duration = 0.5;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.view.window.layer addAnimation:transition forKey:kCATransition];
[self presentViewController:dashboardWorkout animated:false completion:nil];


Swift 2.x

let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
view.window!.layer.addAnimation(transition, forKey: kCATransition)
presentViewController(dashboardWorkout, animated: false, completion: nil)

Seems like the animated parameter in the presentViewController method doesn't really matter in this case of custom transition. It can be of any value, either true or false.

like image 58
tonymontana Avatar answered Oct 22 '22 10:10

tonymontana


Complete code for present/dismiss, Swift 3

extension UIViewController {

    func presentDetail(_ viewControllerToPresent: UIViewController) {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromRight
        self.view.window!.layer.add(transition, forKey: kCATransition)

        present(viewControllerToPresent, animated: false)
    }

    func dismissDetail() {
        let transition = CATransition()
        transition.duration = 0.25
        transition.type = kCATransitionPush
        transition.subtype = kCATransitionFromLeft
        self.view.window!.layer.add(transition, forKey: kCATransition)

        dismiss(animated: false)
    }
}
like image 89
Дмитрий Боровиков Avatar answered Oct 22 '22 08:10

Дмитрий Боровиков


Read up all answers and can't see correct solution. The right way do to so is to make custom UIViewControllerAnimatedTransitioning for presented VC delegate.

So it assumes to make more steps, but the result is more customizable and haven't some side effects, like moving from view together with presented view.

So, assume you have some ViewController, and there is a method for presenting

var presentTransition: UIViewControllerAnimatedTransitioning?
var dismissTransition: UIViewControllerAnimatedTransitioning?    

func showSettings(animated: Bool) {
    let vc = ... create new vc to present

    presentTransition = RightToLeftTransition()
    dismissTransition = LeftToRightTransition()

    vc.modalPresentationStyle = .custom
    vc.transitioningDelegate = self

    present(vc, animated: true, completion: { [weak self] in
        self?.presentTransition = nil
    })
}

presentTransition and dismissTransition is used for animating your view controllers. So you adopt your ViewController to UIViewControllerTransitioningDelegate:

extension ViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return presentTransition
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return dismissTransition
    }
}

So the last step is to create your custom transition:

class RightToLeftTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let toView = transitionContext.view(forKey: .to)!

        container.addSubview(toView)
        toView.frame.origin = CGPoint(x: toView.frame.width, y: 0)

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
            toView.frame.origin = CGPoint(x: 0, y: 0)
        }, completion: { _ in
            transitionContext.completeTransition(true)
        })
    }
}

class LeftToRightTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval = 0.25

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

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let container = transitionContext.containerView
        let fromView = transitionContext.view(forKey: .from)!

        container.addSubview(fromView)
        fromView.frame.origin = .zero

        UIView.animate(withDuration: duration, delay: 0, options: .curveEaseIn, animations: {
            fromView.frame.origin = CGPoint(x: fromView.frame.width, y: 0)
        }, completion: { _ in
            fromView.removeFromSuperview()
            transitionContext.completeTransition(true)
        })
    }
}

In that code view controller is presented over current context, you can make your customizations from that point. Also you may see custom UIPresentationController is useful as well (pass in using UIViewControllerTransitioningDelegate)

like image 60
HotJard Avatar answered Oct 22 '22 10:10

HotJard