Как получить текущий эквивалент ключевого окна для многооконного SceneDelegate Xcode 11?

Я конвертирую свое приложение iOS13 для iPadOS в SceneDelegate (многооконное).

Как я могу получить текущее окно UIWindow из текущего SceneDelegate?

Я знаю, что может получить доступ к текущей сцене, используя UIView.window или же UIViewController.view.window, но у меня есть не UI класс (AppDelegate), где мне нужно получить окно (keyWindow до iOS12), чтобы показать снэк-бар поверх всего.

обычно я делал [UIApplication sharedApplication].keyWindow но сейчас, конечно, это не так.

7 ответов

Swift 5.x / iOS 13.x

Вдохновленный многими решениями, чтобы вернуть свое старое свойство окна (ища его внутри connectedScenes), я реализовал небольшое расширение:

extension UIApplication {
    var currentWindow: UIWindow? {
        connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    }
}

Использование:

if let window = UIApplication.shared.currentWindow { 
   // do whatever you want with window
}

Вам нужно просто перебрать все окна и найти ключевое окно вручную.

for (UIWindow *window in [UIApplication sharedApplication].windows) {
    if (window.isKeyWindow) {
        // you have the key window
        break;
    }
}

НЕ используйтеUISceneActivationStateForegroundActiveкак чек. Это означает, что что-то другое, и люди вводят ошибки, используя логику для поиска первогоUISceneActivationStateForegroundActive оконная сцена.

Похоже, вы, вероятно, хотите перенести эту логику в свой SceneDelegate.

Теперь SceneDelegate знает, связано ли окно со сценой, поэтому может иметь смысл прослушивать каждую подключенную сцену независимо от события, которое ведет закусочную, и отображать его в своем окне. Это приведет к тому, что в каждом видимом окне будет отображаться закусочная (1 или более).

Вы можете попробовать:

    if let window = UIApplication.shared.windows.first(where: { (window) -> Bool in window.isKeyWindow}) {
    //your code
    }

Надеюсь это поможет!

ДляSwiftUI, Протестировано в iOS 16+

      extension UIApplication {
    var currentWindow: UIWindow? {
        connectedScenes
            .compactMap { $0 as? UIWindowScene }
            .first?
            .windows
            .first
    }
}

Это использование.

      guard let anchor = UIApplication.shared.currentWindow else {
   fatalError("Window did not found in Hierarchy")
}

Теперь у вас есть более одного окна, по одному для каждой сцены. Во-первых, вы должны ответить, какой из них вам нужен в момент использования.

Возможно, вы хотите получить окно текущей активной сцены, тогда вы можете использовать это:

    UIWindow* window = nil;
    if (@available(iOS 13.0, *))
    {
        for (UIWindowScene* wScene in [UIApplication sharedApplication].connectedScenes)
        {
            if (wScene.activationState == UISceneActivationStateForegroundActive)
            {
                window = wScene.windows.firstObject;

                break;
            }
        }
    }

Я еще не пробовал это, но вы должны быть в состоянии получить все окна с [UIApplication sharedApplication].windows и затем выберите, хотите ли вы показать снэк-бар на всех окнах или одном окне.

Другие вопросы по тегам