Swift 检测iOS暗模式变化

Swift 检测iOS暗模式变化,swift,ios13,Swift,Ios13,我阅读了有关以下方面的文件: 当用户更改系统外观时,系统会自动要求每个窗口和视图重新绘制自身。在此过程中,系统调用下表中列出的macOS和iOS的几种众所周知的方法来更新您的内容 在遗留应用程序中,我们在每个类的init中将视图创建为惰性变量。这意味着,如果用户进入“设置”并切换到“暗模式”,视图将无法以正确的颜色绘制出来 如果您在这些方法之外进行外观敏感更改,您的应用程序可能无法针对当前环境正确绘制其内容。解决方案是将代码移动到这些方法中 我们的应用程序相当大,将来将进行重构以更好地支持这一点

我阅读了有关以下方面的文件:

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

在遗留应用程序中,我们在每个类的init中将视图创建为惰性变量。这意味着,如果用户进入“设置”并切换到“暗模式”,视图将无法以正确的颜色绘制出来

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

我们的应用程序相当大,将来将进行重构以更好地支持这一点,但我想知道是否有一种方法可以通过通知中心检测到这种变化,就像对Mac OS可以做的那样:


我最终将所有颜色设置移动到所有视图中的layoutSubviews()函数和视图控制器中的viewdilayoutsubviews()

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  // Do sonthing
}

Swift 5:

traitCollectionDidChange也会被调用几次。这就是我检测DarkMode运行时更改和setColor()的方法

在setColors()函数中,我更新颜色。 检测当前配色方案:

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

}
我有这样定义的颜色(对于iOS<13):

例如:

private func setColors() {
  myView.backgroundColor = ColorCompatibility.myOlderiOSCompatibleColorName
}
此外,您可能需要在ViewDiLoad/Will/DidDisplay中调用SetColor,具体取决于您的情况,如下所示:

viewDidLoad() {
...
setColors()
...
}
对于iOS11+,您可以使用“命名颜色”,这是在资产中定义的,在IB中更容易使用


干杯

我认为颜色更适合使用

UIColor.init { (trait) -> UIColor in

    return trait.userInterfaceStyle == .dark ? .label : .black
}

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

只需覆盖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
    }
}
是视图控制器和视图中的一种方法。

Objective-C版本:

if (@available(iOS 12.0, *)) {

    if( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ){
       //is dark
    }else{
        //is light

    }
}

好主意。我决定试一试,到目前为止效果很好。
layoutSubviews
不是这样做的好地方。因为这种方法需要大量的改变,不仅仅是暗模式,看看更多关于[如何在iOS 13中检测光|暗模式改变]()@Sashoy你的答案令人难以置信地误导,你所指的灰显方法和绿色完全与它们的好坏无关。它们是在演示文稿中显示它们何时相关的指标,这就是其他方法变灰的原因。我尝试过很多次使用这种方法,但结果不可靠。每次更改都会触发两次,第二个值始终是前一个值。对我来说,这似乎有点不可靠。你为什么不在这里调用基方法?如果使用此方法,请确保将
super.traitCollectionDidChange(previousTraitCollection)
作为函数的第一行调用!(@andromedainiative,这可能让你免于那些不可靠的结果。)请检查。有人能解释一下
guard UIApplication.shared.applicationState==.inactive else的用途吗?这是否会阻止多次调用该方法?如果是,如何执行?@DavidChopin该行在应用程序未处于非活动状态时导致func提前返回。我不需要那条线,没有它func对我来说非常好。我发现没有那条线我的行为会更好。我也发现没有回报的行为会更好,比如@DavidChopinout@DavidChopin我使用
traitCollectionDidChange
在暗模式更改时更新
CGColors
。如果您有两个选项卡,请更改暗模式,切换到以前未选择的选项卡,然后
ui应用程序.shared.applicationState
不是
.inactive
。这意味着使用
guard
的早期
return
将不会更新屏幕,用户将看到旧的颜色。现在我将省略
防护装置
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
    }
}
if (@available(iOS 12.0, *)) {

    if( self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ){
       //is dark
    }else{
        //is light

    }
}