【问题标题】:How to detect Light\Dark mode change in iOS 13?如何检测 iOS 13 中的 Light\Dark 模式变化?
【发布时间】:2023-03-25 05:17:01
【问题描述】:

某些 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 更改时才触发的正确函数是什么?

【问题讨论】:

    标签: swiftui uikit ios-darkmode uitraitcollection


    【解决方案1】:

    我认为这应该被调用的频率大大降低,加上守卫确保您只对用户界面样式更改做出反应:

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
    
        guard previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle else {
            return
        }
        dropShadowIfNeeded()
    }
    

    【讨论】:

    • 有一个专门用于颜色变化的 API traitCollection.hasDifferentColorAppearance。但在此先感谢。
    • 并且不要忘记 override 关键字,然后,调用 super 的方法以防止出现意外的 not working 情况。
    【解决方案2】:

    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 左右所述。

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

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

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

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

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

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

    如果您只是寻找样式的初始状态,check out this answer here

    【讨论】:

    • 灰色不代表“不好”,绿色不代表“为此而设计”。绿色突出显示仅表示演讲者正在谈论这些方法。 (如果您备份几秒钟,您会看到其他方法也以绿色突出显示。)如果我们给您留下了错误的印象,我很抱歉。
    • 即使理论上保证调用一次以进行更改,当将应用程序置于后台时,有时它会被调用两次(从浅色切换到深色,反之亦然)。看到这个 SO:stackoverflow.com/questions/59139757/…
    • 特征集合发生变化并且方法正在调用,但是if 语句阻止它重复调用@Eugenio
    • 不幸的是,即使使用 @MojtabaHosseini 的 if,我也遇到了重复的呼叫。基本上,当您将应用程序置于后台时,有时会发生的情况是首先颜色外观从浅色变为深色,然后反过来。看看我在上一条评论中发布的 SO。
    【解决方案3】:

    使用 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()
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-01-28
      • 1970-01-01
      • 2014-06-16
      • 2020-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多