Swift:获取暗/亮模式的动态浮点值

Swift: get dynamic float value for dark / light mode

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

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

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

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 指出的那样,你所做的和我所做的唯一真正的区别是我有一个计算的 属性,每次你获取它的值时都会重新计算,而你有一个 属性 的定义和调用初始化器,它在初始化后永远不会改变。

您无法实现与 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
}

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

*感谢 matt 计算的 属性 代码。