Как определить смену режима Свет / Темнота в iOS 13?
Некоторые настройки пользовательского интерфейса, не работающие автоматически с темным / светлым режимом, меняются как 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 ответа
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 - Сессия 214 около 23:30.
Как я и ожидал, эта функция часто вызывается, в том числе при изменении цвета. Наряду со многими другими функциями дляViewController
а также presentationController
. Но есть специальная функция, которая имеет схожую сигнатуру во всехView
представители.
Взгляните на это изображение из этого сеанса:
Серый: звонит, но не подходит для моей проблемы, Зеленый: предназначен для этого
Поэтому я должен вызвать его и проверить внутри этой функции:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
dropShadowIfNeeded()
}
}
Это гарантирует, что будет вызываться только один раз за изменение.
если вы ищете только начальное состояние стиля, посмотрите этот ответ здесь
Я думаю, что это должно вызываться значительно реже, плюс охранник следит за тем, чтобы вы реагировали только на изменения стиля пользовательского интерфейса:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
return
}
dropShadowIfNeeded()
}
С помощью среды выполнения 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()
}
}