【问题标题】:How to present view controller from left to right in iOS?如何在 iOS 中从左到右呈现视图控制器?
【发布时间】:2019-01-11 11:47:09
【问题描述】:

向导航堆栈添加新控制器时:

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

它从右边出现:

如何改变动画的方向,让它从左边出现?

【问题讨论】:

  • 你想推送或展示 ViewController?
  • 提醒一下,这非常违反 Apple 的设计准则,并且可能会让您的用户感到困惑。

标签: ios swift animation uinavigationcontroller


【解决方案1】:
【解决方案2】:

你可以使用第三方库,你可以在github.comcocoacontrols.com作为导航抽屉搜索它们

就我而言,我使用这个 https://github.com/CosmicMind/Material#NavigationDrawer

其他 https://www.cocoacontrols.com/search?q=Drawer

https://github.com/dekatotoro/SlideMenuControllerSwift

https://github.com/jonkykong/SideMenu

【讨论】:

    【解决方案3】:

    Swift 5.1:从不同方向继续前进

    这是一个针对不同 segue 方向的简单扩展。 (在 Swift 5 中测试)

    看起来你想使用 segueFromLeft() 我还添加了一些其他示例。

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

    以下是实现上述扩展的方法:

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

    【讨论】:

    • 这有帮助。我拥有你。
    • 我尝试在操场上对此进行测试,但得到“表达式解析失败,未知错误”。
    • 太棒了!谢谢你。但我有一个问题。如何删除此动画中的阴影?如果我使用默认的 iOS func pushViewController - 新视图下会出现没有阴影。但如果我使用你的代码,我会看到阴影。
    【解决方案4】:
    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)
    

    当你使用 popToViewController 时

     transition.subtype = kCATransitionFromRight
    

    【讨论】:

    • 拯救了我的一天,谢谢
    【解决方案5】:

    好的,这是适合您的插入式解决方案。添加名为LeftToRightTransitionProxy.swift 的文件和下一个内容

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

    你可以这样使用它:

    final class ViewController: UIViewController {
    
        let animationProxy = LeftToRightTransitionProxy()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            animationProxy.setup(with: navigationController!)
        }
    }
    

    此解决方案为向前和向后pushpop)方向提供动画。 这可以在 LeftToRightTransitionProxy 类的 navigationController(_:animationControllerFor:from:to:) 方法中进行控制(只需返回 nil 以删除动画)。

    如果您对UIViewController特定子类 需要此行为,请在navigationController(_:animationControllerFor:from:to:) 方法中进行适当的检查:

    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
    }
    

    【讨论】:

      【解决方案6】:

      这可能对你有帮助

      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)
      

      【讨论】:

        【解决方案7】:

        如果您想学习如何进行自定义转换(即从右到左呈现),那么 this 是一个很好的设置教程。

        您需要做的关键事情是设置过渡委托、自定义演示控制器和自定义动画控制器。

        【讨论】:

          【解决方案8】:

          我使用Hero 作为解决方案。

          import Hero
          

          然后在你要显示新 UIViewController 的地方打开默认动画:

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

          同时指定你的 UINavigationController 将使用 Hero 库:

          self.navigationController?.hero.isEnabled = true
          

          之后,即使你使用标准的 pushViewController 函数,你也会得到预期的结果:

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

          【讨论】:

            猜你喜欢
            • 2016-10-09
            • 1970-01-01
            • 2013-03-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-09
            • 1970-01-01
            • 2016-02-03
            相关资源
            最近更新 更多