Swift:在暗/亮模式下获得动态浮动值

时间:2020-02-23 23:08:22

标签: swift ios-darkmode uitraitcollection

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

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值执行相同的操作,例如具有语义上的float var。这意味着我可以为暗模式和亮模式 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
    }
}()

2 个答案:

答案 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指出的那样,您正在做的事情和我正在做的事情之间的唯一真正区别是,我有一个计算所得的属性,每次获取其值时都会重新计算该属性,而您拥有一个定义和调用初始化器,用于初始化后永不更改的属性。

答案 1 :(得分: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
}

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

*感谢亚光获取计算出的属性代码。