转换到 child UINavigationController 时奇怪的导航栏动画

Strange navigation bar animation when transitioning to a child UINavigationController

我创建了一个小项目来重现这个问题。

唯一的文件是这个...

一小段代码

class RootViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        showBlue()
    }

    @objc func showBlue() {
        let vc = UIViewController()
        vc.view.backgroundColor = .blue

        let nvc = UINavigationController(rootViewController: vc)

        vc.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(showGreen))

        transition(to: nvc)
    }

    @objc func showGreen() {
        let vc = UIViewController()
        vc.view.backgroundColor = .green

        let nvc = UINavigationController(rootViewController: vc)

        vc.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(showBlue))

        transition(to: nvc)
    }

    func transition(to toVC: UIViewController) {
        if let fromVC = children.first {
            transitionWithAnimation(fromVC: fromVC, toVC: toVC)
        } else {
            addWithoutAnimation(child: toVC)
        }
    }

    func addWithoutAnimation(child toVC: UIViewController) {
        addChild(toVC)
        view.addSubview(toVC.view)
        toVC.view.frame = view.bounds
        toVC.didMove(toParent: self)
    }

    func transitionWithAnimation(fromVC: UIViewController, toVC: UIViewController) {
        addChild(toVC)
        toVC.view.frame = view.bounds

        fromVC.willMove(toParent: nil)

        transition(
            from: fromVC,
            to: toVC,
            duration: 1.0,
            options: .transitionCrossDissolve,
            animations: nil) { _ in
                fromVC.removeFromParent()
                toVC.didMove(toParent: self)
        }
    }
}

解释代码

RootViewController 首先做 showBlue。这会添加一个 child UINavigationController 和一个带有蓝色背景的 rootViewController。蓝色视图控制器有一个 Done 按钮,然后指向 showGreen.

showGreen 过渡到具有绿色背景和目标 showBlue.

Done 按钮的 UINavigationController

如我所料

我期望(以及我想要发生的)是导航栏在不调整大小的情况下交叉溶解到位。

问题动画

问题是在动画过渡期间,导航栏有一个奇怪的动画。你可以在这里看到...

关于此的 Apple 文档

所有代码都完全遵循关于将 child 视图控制器添加到自定义容器视图控制器的 Apple 文档... https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html

我尝试过的事情

我也尝试过使用 AutoLayout 约束而不是直接设置视图的框架,但这并没有改变任何东西。

我在新视图控制器的 view 上尝试了 运行 view.setNeedsLayout 然后 view.layoutIfNeeded() 但这似乎也没有解决它。

如果child不是UINavigationController

就没有奇怪的动画

真正奇怪的是,如果您使用任何其他类型的视图控制器(UINavigationController 除外),则不会发生此动画故障。例如:如果其中一个视图控制器是 UITabBarController 那么选项卡就没有这种奇怪的动画。更奇怪的是,如果选项卡包含 UINavigationController 那么它也没有这个动画。从字面上看,如果直接 child 是 UINavigationController.

有没有人遇到过这种情况?你有没有设法阻止奇怪的动画?

如果将转换代码放在 CATransaction 中并使用 kCATransactionDisableActions 键关闭隐式操作,它将解决问题:

    CATransaction.begin()
    CATransaction.setValue(kCFBooleanTrue, forKey:kCATransactionDisableActions)
        
    transition(
        from: fromVC,
        to: toVC,
        duration: 1.0,
        options: [.transitionCrossDissolve],
        animations: nil) { _ in
            fromVC.removeFromParent()
            toVC.didMove(toParent: self)
    }
        
    CATransaction.commit()