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

前端 未结 12 1184
悲&欢浪女
悲&欢浪女 2020-12-04 06:03

I am using presentViewController to present new screen

let dashboardWorkout = DashboardWorkoutViewController()
presentViewController(dashboardWorkout, anima         


        
相关标签:
12条回答
  • 2020-12-04 06:29

    import UIKit and create one extension for UIViewController:

    extension UIViewController {
    func transitionVc(vc: UIViewController, duration: CFTimeInterval, type: CATransitionSubtype) {
        let customVcTransition = vc
        let transition = CATransition()
        transition.duration = duration
        transition.type = CATransitionType.push
        transition.subtype = type
        transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        view.window!.layer.add(transition, forKey: kCATransition)
        present(customVcTransition, animated: false, completion: nil)
    }}
    

    after simlpy call:

    let vC = YourViewController()
    transitionVc(vc: vC, duration: 0.5, type: .fromRight)
    

    from left to right:

    let vC = YourViewController()
    transitionVc(vc: vC, duration: 0.5, type: .fromleft)
    

    you can change the duration with your preferred duration...

    0 讨论(0)
  • 2020-12-04 06:30

    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.

    0 讨论(0)
  • 2020-12-04 06:30

    You can also use custom segue.

    Swift 5

    class SegueFromRight: 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: UIView.AnimationOptions.curveEaseInOut,
                   animations: {
                        dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
                },
                       completion: { finished in
                        src.present(dst, animated: false, completion: nil)
            })
        }
    }
    
    0 讨论(0)
  • 2020-12-04 06:32

    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)
        }
    }
    
    0 讨论(0)
  • 2020-12-04 06:33

    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)

    0 讨论(0)
  • 2020-12-04 06:38

    Try this.

    let transition: CATransition = CATransition()
    transition.duration = 0.3
    
    transition.type = kCATransitionReveal
    transition.subtype = kCATransitionFromLeft
    self.view.window!.layer.addAnimation(transition, forKey: nil)
    self.dismissViewControllerAnimated(false, completion: nil)
    
    0 讨论(0)
提交回复
热议问题