iOS 13 中 UIWindow 在内容上方未显示

48

我正在升级我的应用程序,以使用iOS 13中定义的新的UIScene模式,但是应用程序的关键部分已经停止工作。 我一直在使用UIWindow来覆盖屏幕上的当前内容,并向用户呈现新信息,但在我目前使用的测试版(iOS + XCode beta 3)中,窗口将出现,但随即消失。

这是我曾经使用的代码,但现在无法工作:

let window = UIWindow(frame: UIScreen.main.bounds)
let viewController = UIViewController()
viewController.view.backgroundColor = .clear
window.rootViewController = viewController
window.windowLevel = UIWindow.Level.statusBar + 1
window.makeKeyAndVisible()
viewController.present(self, animated: true, completion: nil)

我尝试了许多方法,包括使用 WindowScenes 来呈现新的 UIWindow,但是无法找到实际的文档或示例。

我的其中一次尝试(没有成功 - 窗口出现后立即消失)

let windowScene = UIApplication.shared.connectedScenes.first
if let windowScene = windowScene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    let viewController = UIViewController()
    viewController.view.backgroundColor = .clear
    window.rootViewController = viewController
    window.windowLevel = UIWindow.Level.statusBar + 1
    window.makeKeyAndVisible()
    viewController.present(self, animated: true, completion: nil)
}

有人在 iOS 13 beta 中已经成功实现过这个了吗?

谢谢

编辑

问这个问题和最终版本的 iOS 13 发布之间已经过去了一段时间。下面有很多答案,但几乎所有答案都包括一个要点 - 向 UIWindow 添加强引用(strong/stronger reference)。你可能需要包括一些关于新场景(Scenes)的代码,但先尝试添加强引用。


3
你需要保留对窗口对象的引用。 - Leo Dabus
1
@LeoDabus 我正在尝试在当前窗口上呈现一个新窗口?我应该在哪里使用我的窗口对象引用?在13 beta之前,顶部代码块完美地工作。 - mHopkins
1
将窗口声明移出闭包。 - Leo Dabus
1
尝试使用 var window: UIWindow?,如果可以将 windowScene 转换为 UIWindowScene 类型,则执行以下操作:window = .init(windowScene: windowScene)然后使用可选链式调用 window?.whatever - Leo Dabus
@LeoDabus 啊,我明白了。我尝试过了,但是没有成功。WindowwindowScene都是已经成功引用的实际对象,问题不在于找不到这些对象,而是我得到了与顶部代码块相同的行为。谢谢。 - mHopkins
@LeoDabus 谢谢您建议保留对窗口的引用。这为我解决了同样的问题! - Brian Boyle
12个回答

0

除了关于创建 UIWindow 引用并以模态方式呈现的答案之外,我还包括了代码中关于如何解除它的一部分。

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
Swift 4.2 iOS 13 UIAlertController 扩展

这段代码在 iOS 11、12 和 13 上完全可用。

import Foundation
import UIKit

extension UIAlertController{
    private struct AssociatedKeys {
        static var alertWindow = "alertWindow"
    }
    var alertWindow:UIWindow?{
        get{
            guard let alertWindow = objc_getAssociatedObject(self, &AssociatedKeys.alertWindow) as? UIWindow else {
                return nil
            }
            return alertWindow
        }
        set(value){
            objc_setAssociatedObject(self,&AssociatedKeys.alertWindow,value,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func show(animated:Bool) {
        self.alertWindow = UIWindow(frame: UIScreen.main.bounds)
        self.alertWindow?.rootViewController = UIViewController()
        self.alertWindow?.windowLevel = UIWindow.Level.alert + 1
        if #available(iOS 13, *){
            let mySceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate
            mySceneDelegate!.window?.rootViewController?.present(self, animated: animated, completion: nil)
        }
        else{
            self.alertWindow?.makeKeyAndVisible()
            self.alertWindow?.rootViewController?.present(self, animated: animated, completion: nil)
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接