UIWindow not showing over content in iOS 13

后端 未结 12 1657
野的像风
野的像风 2020-12-07 17:41

I am upgrading my app to use the new UIScene patterns as defined in iOS 13, however a critical part of the app has stopped working. I have been using a UI

相关标签:
12条回答
  • 2020-12-07 18:16

    Here are the steps to present a view controller in a new window on iOS 13:

    1. Detect focused UIWindowScene.
    extension UIWindowScene {
        static var focused: UIWindowScene? {
            return UIApplication.shared.connectedScenes
                .first { $0.activationState == .foregroundActive && $0 is UIWindowScene } as? UIWindowScene
        }
    }
    
    1. Create UIWindow for the focused scene.
    if let window = UIWindowScene.focused.map(UIWindow.init(windowScene:)) {
      // ...
    }
    
    1. Present UIViewController in that window.
    let myViewController = UIViewController()
    
    if let window = UIWindowScene.focused.map(UIWindow.init(windowScene:)) {
        window.rootViewController = myViewController
        window.makeKeyAndVisible()
    }
    
    0 讨论(0)
  • 2020-12-07 18:23

    Need have pointer a created window for ios13.

    example my code:

     extension UIAlertController {
    
        private static var _aletrWindow: UIWindow?
        private static var aletrWindow: UIWindow {
            if let window = _aletrWindow {
                return window
            } else {
                let window = UIWindow(frame: UIScreen.main.bounds)
                window.rootViewController = UIViewController()
                window.windowLevel = UIWindowLevelAlert + 1
                window.backgroundColor = .clear
                _aletrWindow = window
                return window
            }
        }
    
        func presentGlobally(animated: Bool, completion: (() -> Void)? = nil) {
            UIAlertController.aletrWindow.makeKeyAndVisible()
            UIAlertController.aletrWindow.rootViewController?.present(self, animated: animated, completion: completion)
        }
    
        open override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
            UIAlertController.aletrWindow.isHidden = true
        }
    
    }
    

    use:

    let alert = UIAlertController(...
    ...
    
    alert.presentGlobally(animated: true)
    
    0 讨论(0)
  • 2020-12-07 18:25

    In addition to the answers about creating a reference to UIWindow and then presenting modally, I've included a section of my code on how I'm dismissing it.

    class PresentingViewController: UIViewController {
        private var coveringWindow: UIWindow?
    
      func presentMovie() {
        let playerVC = MoviePlayerViewController()
        playerVC.delegate = self
        playerVC.modalPresentationStyle = .overFullScreen
        playerVC.modalTransitionStyle = .coverVertical
    
        self.coverPortraitWindow(playerVC)
      }
    
      func coverPortraitWindow(_ movieController: MoviePlayerViewController) {
    
        let windowScene = UIApplication.shared
            .connectedScenes
            .filter { $0.activationState == .foregroundActive }
            .first
        if let windowScene = windowScene as? UIWindowScene {
            self.coveringWindow = UIWindow(windowScene: windowScene)
    
            let rootController = UIViewController()
            rootController.view.backgroundColor = .clear
    
            self.coveringWindow!.windowLevel = .alert + 1
            self.coveringWindow!.isHidden = false
            self.coveringWindow!.rootViewController = rootController
            self.coveringWindow!.makeKeyAndVisible()
    
            rootController.present(movieController, animated: true)
        }
      }
    
      func uncoverPortraitWindow() {
        guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
            let sceneDelegate = windowScene.delegate as? SceneDelegate
            else {
                return
        }
        sceneDelegate.window?.makeKeyAndVisible()
        self.coveringWindow = nil
      }
    
    }
    
    0 讨论(0)
  • 2020-12-07 18:26

    Here's a bit hacky way of holding a strong reference to created UIWindow and releasing it after presented view controller is dismissed and deallocated. Just make sure you don't make reference cycles.

    private final class WindowHoldingViewController: UIViewController {
    
        private var window: UIWindow?
    
        convenience init(window: UIWindow) {
            self.init()
    
            self.window = window
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = UIColor.clear
        }
    
        override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
            let view = DeallocatingView()
            view.onDeinit = { [weak self] in
                self?.window = nil
            }
            viewControllerToPresent.view.addSubview(view)
    
            super.present(viewControllerToPresent, animated: flag, completion: completion)
        }
    
        private final class DeallocatingView: UIView {
    
            var onDeinit: (() -> Void)?
    
            deinit {
                onDeinit?()
            }
        }
    }
    

    Usage:

    let vcToPresent: UIViewController = ...
    let window = UIWindow() // or create via window scene
    ...
    window.rootViewController = WindowHoldingViewController(window: window)
    ...
    window.rootViewController?.present(vcToPresent, animated: animated, completion: completion)
    
    0 讨论(0)
  • 2020-12-07 18:29

    You can try like this:

    extension UIWindow {
        static var key: UIWindow? {
            if #available(iOS 13, *) {
                return UIApplication.shared.windows.first { $0.isKeyWindow }
            } else {
                return UIApplication.shared.keyWindow
            }
        }
    }
    

    Usage:

    if let rootVC = UIWindow.key?.rootViewController {
        rootVC.present(nextViewController, animated: true, completion: nil)
    }
    

    Keep Coding........ :)

    0 讨论(0)
  • 2020-12-07 18:32

    I was experiencing the same problems while upgrading my code for iOS 13 scenes pattern. With parts of your second code snippet I managed to fix everything so my windows are appearing again. I was doing the same as you except for the last line. Try removing viewController.present(...). Here's my code:

    let windowScene = UIApplication.shared
                    .connectedScenes
                    .filter { $0.activationState == .foregroundActive }
                    .first
    if let windowScene = windowScene as? UIWindowScene {
        popupWindow = UIWindow(windowScene: windowScene)
    }
    

    Then I present it like you do:

    popupWindow?.frame = UIScreen.main.bounds
    popupWindow?.backgroundColor = .clear
    popupWindow?.windowLevel = UIWindow.Level.statusBar + 1
    popupWindow?.rootViewController = self as? UIViewController
    popupWindow?.makeKeyAndVisible()
    

    Anyway, I personally think that the problem is in viewController.present(...), because you show a window with that controller and immediately present some 'self', so it depends on what 'self' really is.

    Also worth mentioning that I store a reference to the window you're moving from inside my controller. If this is still useless for you I can only show my small repo that uses this code. Have a look inside AnyPopupController.swift and Popup.swift files.

    Hope that helps, @SirOz

    0 讨论(0)
提交回复
热议问题