11

某些 UI 设置无法自动使用暗/亮模式更改为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()
}

但是这个函数被称为A LOT。只有在userInterfaceStyle更改时才触发的正确功能是什么?

4

3 回答 3

20

SwiftUI

键上有一个简单的环境变量\.colorScheme

struct ContentView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text(colorScheme == .dark ? "Its Dark" : "Its. not dark! (Light)")
    }
}

UIKit

正如WWDC 2019 - 23:30 左右的Session 214中所述。

正如我所料,这个函数被调用了很多,包括颜色变化时。除了 和 的许多其他功能ViewControllerpresentationController。但是有一些特殊的功能设计用于在所有View代表中具有相似的签名。

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

WWDC 2019 - 会议 214

灰色:打电话但对我的问题没有好处,绿色:为此而设计

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

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        dropShadowIfNeeded()
    }
}

这将保证每次更改只调用一次。

如果您只是在寻找样式的初始状态,请在此处查看此答案

于 2019-09-19T18:36:52.847 回答
2

我认为这应该很少被调用,而且守卫确保你只对用户界面样式的变化做出反应:

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

    guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
        return
    }
    dropShadowIfNeeded()
}
于 2019-09-19T18:36:21.827 回答
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()
    }
}
于 2019-09-25T04:28:36.617 回答