用户更改设置中的外观时,应用程序不会更新,并且traitCollectionDidChange不会触发

时间:2020-03-04 18:55:05

标签: ios swift ios-darkmode uitraitcollection

在我的应用中,我允许用户覆盖设备上设置的外观。如果他们要覆盖系统范围的外观,则下面是处理更新UI的类:

class UserInterfaceStyleController {

init() {
    self.handleUserInterfaceStyleChange()
    NotificationCenter.default.addObserver(self, selector: #selector(self.handleUserInterfaceStyleChange), name: Notification.Name(OMGNotification.changeBizzaroMode.rawValue), object: nil)
}

@objc func handleUserInterfaceStyleChange() {
    if #available(iOS 13.0, *) {
        let windows = UIApplication.shared.windows
        for window in windows {
            if UIScreen.main.traitCollection.userInterfaceStyle == .light {
                if UserDefaults.standard.bizzaroMode {
                    window.overrideUserInterfaceStyle = .dark
                } else {
                    window.overrideUserInterfaceStyle = .light
                }
            }
            if UIScreen.main.traitCollection.userInterfaceStyle == .dark {
                if UserDefaults.standard.bizzaroMode {
                    window.overrideUserInterfaceStyle = .light
                } else {
                    window.overrideUserInterfaceStyle = .dark
                }
            }
            window.subviews.forEach({ view in
                view.layoutIfNeeded()
            })
        }
    }
}

这有效-用户按下开关,然后应用更改userInterfaceStyle。问题在于,当用户更改系统范围的外观(在设置中设置亮或暗模式)时,该应用程序不会自动更改外观,仅当用户手动设置时才会更改。

所以我假设当用户在系统范围内对其进行更改时,我需要做一些工作,而traitCollectionDidChange似乎是我需要使用的。问题是,当用户更改设置的外观时,它不会触发,只有在我的应用中手动设置时,它才会触发。 我已经在viewController中获得了以下代码来进行测试:

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    // Lots of stuff

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        print("We have a style mode change")
    }

    // Lots more stuff
}

当我手动覆盖时,它会显示“我们更改了样式模式”。当我进入设置并切换系统范围的外观时,traitCollectionDidChange不会触发。

我发誓我目前可以正常工作,但是当我使用overrideUserInterfaceStyle并花了很多代码更改后,我一直在尝试解决一些奇怪的问题。

我认为我缺少明显的东西。在我开始允许用户覆盖之前,在系统范围内更改外观而根本没有代码的情况下,应用程序会在后台自动切换。现在不会,并且traitCollectionDidChange不会触发。我想念什么或做错什么?如果有帮助,很高兴提供更多代码。

谢谢!

1 个答案:

答案 0 :(得分:6)

问题是您覆盖了用户界面样式,这导致任何系统更改都不会传播到您的窗口。您需要将overrideUserInterfaceStyle设置为.unspecified,否则系统将不会在更改时在视图堆栈中调用traitCollectionDidChange方法。

在我们的应用中,我们为用户提供了三个选项:自动,明暗两种,其中每个选项仅将overrideUserInterfaceStyle设置为适当的选项。

顺便说一句,您无需在所有子视图上调用layoutIfNeeded()-设置overrideUserInterfaceStyle会自动重绘。