首页 > 解决方案 > UIViewController生命周期破iOS13,makeKeyAndVisible()好像不能操作?

问题描述

我有一个自定义 UIStoryboardSegue 可以在 iOS12.* 中按需要工作。

目标视图控制器之一是 UITabbarController:对于每个选项卡,我都有一个嵌入在导航控制器中的控制器。

不幸的是,对于 iOS13.*,这不起作用:视图控制器生命周期被破坏,不再调用 viewXXXAppear() 和 willTransition() 方法。

看起来 makeKeyAndVisible() 没有效果?!

在底部查看屏幕 UI 如何在没有调用 viewWillAppear() 的情况下出现问题。

一个可怕的临时解决方法

我不得不拉扯我的头发,但是我找到了一个我公开的修复程序(我必须动态添加一个导航控制器)。

这弄乱了 vc 层次结构:你有更好的解决方案吗?

public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
    override public func perform() {

        guard let window = UIApplication.shared.delegate?.window as? UIWindow,
            let sourceView = source.view,
            let destinationView = destination.view else {
            super.perform()
            return
        }

        let screenWidth  = UIScreen.main.bounds.size.width
        let screenHeight = UIScreen.main.bounds.size.height

        destinationView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)

        window.insertSubview(destinationView, aboveSubview: sourceView)


        // **My fix**
        if #available(iOS 13,*) {
            // I introduced an invisible navigation controller starting in iOS13 otherwise, my controller attached to the tabbar thru a navigation, dont work correctly, no viewXAppearis called.
            let navigationController = UINavigationController.init(rootViewController: self.destination)
            navigationController.isNavigationBarHidden = true
            window.rootViewController = navigationController
        }
        else {
            window.rootViewController = self.destination
        }

        window.makeKeyAndVisible()
    }
}

用户界面被破坏

标签: uiviewcontrolleruistoryboardsegueios13swift5

解决方案


我找到了一个解决方案,这要归功于使用自定义 segue 对开始/结束外观转换的不平衡调用 这里发生的情况是目标视图控制器的创建和附加发生了两次,而第一个发生得太快了。所以你需要做的是:

public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
    override public func perform() {

        guard let window = UIApplication.shared.delegate?.window as? UIWindow,
            let sourceView = source.view,
            let destinationView = destination.view else {
            super.perform()
            return
        }

        let screenWidth  = UIScreen.main.bounds.size.width
        let screenHeight = UIScreen.main.bounds.size.height

        let mock = createMockView(view: desination.view)
        window.insertSubview(mock, aboveSubview: sourceView)

        //DO SOME ANIMATION HERE< MIGHT NEED TO DO mock.alpha = 0

        //after the animation is done:
        window.rootViewController = self.destination
        mock.removeFromSuperview()
    }

    func createMockView(view: UIView) -> UIImageView {
        UIGraphicsBeginImageContextWithOptions(view.frame.size, true, UIScreen.main.scale)

        view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
        let image = UIGraphicsGetImageFromCurrentImageContext()

        UIGraphicsEndImageContext()
        return UIImageView(image: image)    
    }   
}

推荐阅读