检测iOS暗模式更改

and*_*ive 7 swift ios13

我通读了有关以下内容的文档:https : //developer.apple.com/documentation/appkit/supporting_dark_mode_in_your_interface

当用户更改系统外观时,系统会自动要求每个窗口和视图重绘自身。在此过程中,系统将为macOS和iOS调用下表中列出的几种众所周知的方法来更新您的内容。

在我们的旧版应用程序中,我们在每个类的初始化中将我们的视图创建为惰性变量。这意味着如果用户进入设置并切换到暗模式,则不会以正确的颜色绘制出w。

如果您在这些方法之外进行外观敏感的更改,则您的应用可能无法针对当前环境正确绘制其内容。解决方案是将代码移入这些方法。

我们的应用程序很大,将来会进行重构以更好地支持此功能,但我想知道是否可以通过通知中心检测到此更改,例如可以对Mac OS进行的操作:

如何使用Swift 3检测macOS默认模式与暗模式之间的切换

Ela*_*los 12

我认为颜色更好用

UIColor.init { (trait) -> UIColor in

    return trait.userInterfaceStyle == .dark ? .label : .black
}
Run Code Online (Sandbox Code Playgroud)

因为这样如果系统改变,颜色也会自动改变。


Har*_*kar 12

只需覆盖 iOS 13 的方法即可检测暗光模式更改 swift 5。

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    if #available(iOS 13.0, *) {
        if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
            if traitCollection.userInterfaceStyle == .dark {
                //Dark
            }
            else {
                //Light
            }
        }
    } else {
        // Fallback on earlier versions
    }
}
Run Code Online (Sandbox Code Playgroud)

traitCollectionDidChange 是 ViewControllers 和 Views 中的一个方法。


Sas*_*sho 7

Swift 5:

traitCollectionDidChange also gets called a few times. This is how I detect DarkMode runtime change and setColors() only once.

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        guard UIApplication.shared.applicationState == .inactive else {
            return
        }

        setColors()
    }
Run Code Online (Sandbox Code Playgroud)

In setColors() func I update the colors. Detecting current colorScheme:

extension UIViewController {
    var isDarkMode: Bool {
        if #available(iOS 13.0, *) {
            return self.traitCollection.userInterfaceStyle == .dark
        }
        else {
            return false
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

I have colors defined like this (for iOS < 13):

enum ColorCompatibility {
    static var myOlderiOSCompatibleColorName: UIColor {
        if UIViewController().isDarkMode {
            return UIColor(red: 33, green: 35, blue: 37, alpha: 0.85)
        }
        else {
            return UIColor(hexString: "#F3F3F3", alpha: 0.85)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Example:

private func setColors() {
  myView.backgroundColor = ColorCompatibility.myOlderiOSCompatibleColorName
}
Run Code Online (Sandbox Code Playgroud)

Also you might need to call setColors in ViewDidLoad/Will/DidAppear depending on your case like this:

viewDidLoad() {
...
setColors()
...
}
Run Code Online (Sandbox Code Playgroud)

For iOS11+ you could use "named Colors", defined in Assets and much easier to use in IB.

Cheers