如何在 iOS 13 中检测 Light\Dark 模式变化?
How to detect Light\Dark mode change in iOS 13?
某些 UI 设置不会自动与 Dark/Light 模式一起工作,而更改为 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
更改时才触发的正确函数是什么?
我认为调用它的频率应该大大降低,而且守卫确保您只对用户界面样式更改做出反应:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
return
}
dropShadowIfNeeded()
}
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 - Session 214 中描述的那样 23:30。
如我所料,这个函数被调用了很多次,包括当颜色改变时。除了 ViewController
和 presentationController
的许多其他功能。但是有一些特殊的功能设计用于在所有 View
代表中具有相似的签名。
看看这张会话中的图片:
灰色:呼吁但对我的问题不利,绿色:为此设计
所以我应该调用它并在这个函数中检查它:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
dropShadowIfNeeded()
}
}
这将保证每次更改只调用一次。
如果您只是寻找样式的初始状态,check out this answer here
借助RxSwift和ObjectiveC runtime,无需继承即可实现
这里是封装版本:
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()
}
}
某些 UI 设置不会自动与 Dark/Light 模式一起工作,而更改为 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
更改时才触发的正确函数是什么?
我认为调用它的频率应该大大降低,而且守卫确保您只对用户界面样式更改做出反应:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
return
}
dropShadowIfNeeded()
}
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 - Session 214 中描述的那样 23:30。
如我所料,这个函数被调用了很多次,包括当颜色改变时。除了 ViewController
和 presentationController
的许多其他功能。但是有一些特殊的功能设计用于在所有 View
代表中具有相似的签名。
看看这张会话中的图片:
灰色:呼吁但对我的问题不利,绿色:为此设计
所以我应该调用它并在这个函数中检查它:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
dropShadowIfNeeded()
}
}
这将保证每次更改只调用一次。
如果您只是寻找样式的初始状态,check out this answer here
借助RxSwift和ObjectiveC runtime,无需继承即可实现
这里是封装版本:
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()
}
}