【问题标题】:Swift: get dynamic float value for dark / light modeSwift:获取暗/亮模式的动态浮点值
【发布时间】:2020-06-07 14:26:03
【问题描述】:

我经常通过以下方式使用语义颜色来为深色模式和浅色模式提供动态颜色。使用这种方法,当用户切换暗/亮模式时,颜色也会在运行时更新:

public static var bw100: UIColor = {
    if #available(iOS 13, *) {
        return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in
            if UITraitCollection.userInterfaceStyle == .dark {
                // Return the color for Dark Mode
                return .black
            } else {
                // Return the color for Light Mode
                return .white
            }
        }
    } else {
        // Return a fallback color for iOS 12 and lower.
        return .white
    }
}()

现在我想对Float 值做同样的事情,比如拥有一个语义浮点变量。这意味着我可以为暗模式和亮模式访问不同的浮点值 AND 如果用户切换暗/亮模式,该值将在运行时适应。我找不到解决方案。

这不起作用,因为它不会在运行时更新。暗/亮模式切换后必须重启应用:

 public static var myFloat: Float = {
    if #available(iOS 13.0, *) {
        if UITraitCollection.current.userInterfaceStyle == .dark {
            return 0.9
        }
        else {
            return 0.1
        }
    }
    return 0.1
}()

这也不起作用(尝试了与上述工作类似的方法),但在这里我收到错误 Initializer init(_:) requires that (UITraitCollection) -> Float conforms to BinaryInteger

public static var myFloat: Float = {
    if #available(iOS 13, *) {
        return Float { (UITraitCollection: UITraitCollection) -> Float in
            if UITraitCollection.userInterfaceStyle == .dark {
                // Return the Float for Dark Mode
                return 0.9
            } else {
                // Return the Float for Light Mode
                return 0.1
            }
        }
    } else {
        // Return a fallback for iOS 12 and lower.
        return 0.1
    }
}()

【问题讨论】:

    标签: swift ios-darkmode uitraitcollection


    【解决方案1】:

    您无法实现与UIColorFloat 一起工作的相同方式,因为UIColor 有一个特殊的初始化程序,可以直接更改界面样式。但是,解决方案仍然相当简单,因为您必须如前所述,通过实现 traitCollectionDidChange(_:) 来监听界面样式更改并手动重新计算您的数据。
    以下代码应该为您实现它:

    // ViewController.swift
    
    var myStoredFloat: Float = 1.0 {
        willSet {
            print(newValue)
        }
    }
    
    var myComputedFloat: Float {
        let tc = UITraitCollection.current
        let mode = tc.userInterfaceStyle
        if #available(iOS 13.0, *) {
            return (mode == .light ? 1 : 0)
        }
        return 1
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        self.myStoredFloat = self.myComputedFloat
    }
    

    当然你可以完全摆脱存储属性,如果你不依赖它而只使用计算属性。

    *感谢 ma​​tt 提供计算的属性代码。

    【讨论】:

      【解决方案2】:

      这对我来说是实时的,并且非常接近你所拥有的:

      static var myFloat : Float {
          let tc = UITraitCollection.current
          let mode = tc.userInterfaceStyle
          if #available(iOS 13.0, *) {
              return (mode == .light ? 1 : 0)
          }
          return 1
      }
      

      正如 Leo Dabus 所指出的,你所做的和我所做的唯一真正的区别是,我有一个计算属性,每次你获取它的值时都会重新计算它,而你有一个为一个在初始化后永远不会改变的属性定义并调用初始化器。

      【讨论】:

      • 我相信 OP 希望浮点值在用户切换到暗/亮模式时自动更改,就像 UIColor 一样。为此,您必须实现 traitCollectionDidChange(_:) 并重新使用计算属性。
      • @Eilon 它确实会自动更改,但您当然必须再次询问。换句话说,浮点值对于当前特征集合总是正确的。还能要求什么呢?语义颜色的工作方式相同。
      • @LeoDabus 很好。我试图用“几乎相同”来表达的是,他的一般技术在我看来是在正确的轨道上。我将修改我的答案以消除其中的奥秘。
      • @matt 不幸的是,这不是我想要的方式。正如@Eilon 提到的,当用户在运行时切换暗/亮模式时,我需要让浮点值自动更改。如果您查看我的第一个带有 UIColor 的代码块,这正是这样做的。我可以只使用bw100 var,它会自动更新,我不需要重新获取(这需要额外的代码实现来检查暗/亮模式的切换)
      • 但这没有任何意义。颜色是一类。它是一个具有持久性的对象,可以实时更改其显示以响应明暗模式的变化,如按钮或其他视图。浮点数只是计算期间使用的值;它仅在您获取和使用它的那一刻存在。一个可以神奇地改变自己并扰乱它所依赖的所有计算的数字将是一个怪物。当特征集合发生变化时,由重新计算,我的解决方案可以让你这样做。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      • 2021-09-12
      • 1970-01-01
      • 2020-04-12
      • 2021-08-12
      • 2023-02-10
      相关资源
      最近更新 更多