如何检测iOS 13中的明暗模式更改?

时间:2019-09-19 18:16:02

标签: swiftui uitraitcollection ios-darkmode

某些用户界面设置无法自动使用“暗/亮”模式更改为UIColor。例如层中的shadow。因为我需要在暗和亮模式下删除阴影,所以需要在某个地方放置updateShadowIfNeeded()函数。我知道如何检测当前的模式:

func dropShadowIfNeeded() {
    switch traitCollection.userInterfaceStyle {
    case .dark: removeShadow()
    case .light: dropShadowIfNotDroppedYet()
    default: assertionFailure("Unknown userInterfaceStyle")
    }
}

现在,我将函数放在layoutSubviews中,因为每次外观更改时都会调用该函数:

override func layoutSubviews() {
    super.layoutSubviews()
    dropShadowIfNeeded()
}

但是此功能被称为很多。仅在userInterfaceStyle更改后才能触发的正确功能是什么?

3 个答案:

答案 0 :(得分:3)

我在WWDC 2019 - Session 214找到了答案,大约是23:30。

正如我预期的那样,包括更改颜色时,都会调用此函数。除了ViewControllerpresentationController的许多其他功能之外。但是有一个专门设计的功能,在所有View代表中都有类似的签名。

看看该会话中的这张图片:

WWDC 2019 - Session 214

灰色:打电话,但不适合我的问题,绿色:专为此设计

所以我应该调用它并在此函数中检查它:

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

    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        dropShadowIfNeeded()
    }
}

这将确保每次更改仅被调用一次。

答案 1 :(得分:1)

我认为应该不那么频繁地调用它,此外,防护措施还可以确保您仅对用户界面样式更改做出反应:

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

    guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
        return
    }
    dropShadowIfNeeded()
}

答案 2 :(得分:0)

使用RxSwift和ObjectiveC运行时,无需继承即可实现

这是封装的版本:

import UIKit
import RxSwift
import RxCocoa

enum SystemTheme {
    static func get(on view: UIView) -> UIUserInterfaceStyle {
        view.traitCollection.userInterfaceStyle
    }

    static func observe(on view: UIView) -> Observable<UIUserInterfaceStyle> {
        view.rx.methodInvoked(#selector(UIView.traitCollectionDidChange(_:)))
            .map { _ in SystemTheme.get(on: view) }
            .distinctUntilChanged()
    }
}