在UINavigationController的堆栈导航

时间:2019-05-04 10:20:38

标签: swift uinavigationcontroller segue transition poptoviewcontroller

使用Swift-5.0.1,Xcode-10.2.1,iOS-12.2和

我发现一个非常奇怪的问题(已经占用了我太多的时间):

我的带有UINavigationController的导航堆栈运行良好。我可以从一个ViewController推送并弹出到下一个。以我为例,我将Coordinator模式与Router配合使用(但是我想这对这个问题并不重要)。

我在UINavigationController上使用两种方法在导航堆栈中向后弹出

  1. popViewController
  2. popToRootViewController

想法是使用popViewController返回堆栈中的一个ViewController。并使用popToRootViewController返回到堆栈中的第一个ViewController。到目前为止,一切都很好!

但是现在问题出在

如果我对popBack-navigation-transitions使用自定义动画过渡,事情就搞砸了!

更确切地说,使用popToRootViewController进行自定义过渡的导航栏已完全混乱,无法正确制作动画!!!!

“不正确”的意思是:导航栏会立即弹出而不是动画。

使用popViewController时,一切正常,导航栏按预期完成了平滑过渡。

为什么在导航栏动画方面popViewControllerpopToRootViewController之间的区别?

我知道我也可以使用Segue进行自定义动画。但是我不想使用Segue,因为它可以防止代码去耦,从而避免测试。我真的很想保留我的协调器和路由器,并使用UINavigationController-Delegate动画化过渡。

以下是展示区别的视频:

->屏幕内容无关紧要。观看标题以查看哪个页面-nr,并观察导航栏动画。

->请观察导航栏,并清楚注意从第3页到第2页的转换与从第3页到第1页的转换之间的区别。

->您可以清楚地注意到,从第3页到第1页的过渡的导航栏是瞬时的,而第1页的其余部分按预期淡入(因为它不应该-NavBar太快了) !!!)

->对于从第3页到第2页的过渡,所有内容都会进行动画处理,包括导航栏以及页面的所有其余部分(应该是!!)

enter image description here

这是我的代码:

popViewController调用:

let t = CustomFadeTransition(withDuration: 1.0)
self.router.popModule(transition: t, animated: true)

popToRootViewController调用:

let t = CustomFadeTransition(withDuration: 1.0)
self.router.popToRootModuleWithTransition(transition: t, animated: true)

具有过渡委托方法(证明)的路由器实现

final class Router: NSObject, RouterProtocol {

    private weak var rootController: UINavigationController?
    private var completions: [UIViewController : () -> Void]
    private var transition: UIViewControllerAnimatedTransitioning?

    // ...

    func popModule(transition: UIViewControllerAnimatedTransitioning?, animated: Bool) {
        self.transition = transition
        let _ = rootController?.popViewController(animated: animated)
    }

    func popToRootModuleWithTransition(transition: UIViewControllerAnimatedTransitioning?, animated: Bool) {
        self.transition = transition
        let _ = self.rootController?.popToRootViewController(animated: animated) 
    }

}

extension Router: UINavigationControllerDelegate, UIViewControllerTransitioningDelegate {

    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self.transition
    }

    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return self.transition
    }
}

CustomFadeTransition实现(此处并不重要,因为任何Transition都显示了混乱的导航栏...但是要在此处完成代码。)

class CustomFadeTransition: NSObject, UIViewControllerAnimatedTransitioning {
    let duration: TimeInterval
    let presenting: Bool

    init(withDuration: TimeInterval = 0.2, presenting: Bool = true) {
        self.duration = withDuration
        self.presenting = presenting
        super.init()
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let from   = transitionContext.viewController(forKey: .from)!
        let to     = transitionContext.viewController(forKey: .to)!
        let container = transitionContext.containerView
        if presenting {
            container.addSubview(to.view)
            to.view.alpha = 0.0
        } else {
            container.insertSubview(to.view, belowSubview: from.view)
        }
        UIView.animate(withDuration: (duration * 2), animations: {
            if self.presenting {
                to.view.alpha = 1.0
            } else {
                from.view.alpha = 0.0
            }
        }, completion: { value in
            let success = !transitionContext.transitionWasCancelled
            if !success {
                to.view.removeFromSuperview()
            }
            transitionContext.completeTransition(success)
        })
    }

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

0 个答案:

没有答案