为什么NSColor.labelColor根据背景颜色变化?

时间:2019-05-08 19:24:06

标签: swift macos cocoa nscolor

我正在开发可可应用程序,我发现只要将NSTextField的字体颜色设置为NSColor。 labelColor,字体将根据NSTextField的背景颜色而改变。

例如,当我将背景色设置为白色时,字体变为黑色。

但是当我将背景色设置为黑色时,字体变成白色。

我想定义一个NSColor来达到相同的效果。如何实现?

1 个答案:

答案 0 :(得分:3)

如果要传递任何颜色,然后确定哪种文本颜色更理想-黑色或白色-首先需要确定该颜色的亮度(以sRGB为单位)。为此,我们可以先转换为灰度,然后检查黑色与白色之间的对比度。

请查看此整洁的扩展程序:

extension NSColor {

    /// Determine the sRGB luminance value by converting to grayscale. Returns a floating point value between 0 (black) and 1 (white).
    func luminance() -> CGFloat {
        var colors: [CGFloat] = [redComponent, greenComponent, blueComponent].map({ value in
            if value <= 0.03928 {
                return value / 12.92
            } else {
                return pow((value + 0.055) / 1.055, 2.4)
            }
        })
        let red = colors[0] * 0.2126
        let green = colors[1] * 0.7152
        let blue = colors[2] * 0.0722
        return red + green + blue
    }

    func contrast(with color: NSColor) -> CGFloat {
        return (self.luminance() + 0.05) / (color.luminance() + 0.05)
    }

}

现在,我们可以通过检查黑色背景色与白色之间的对比,来确定是否应使用黑色或白色作为文本。

// Background color for whatever UI component you want.
let backgroundColor = NSColor(red: 0.5, green: 0.8, blue: 0.2, alpha: 1.0)
// Contrast of that color w/ black.
let blackContrast = backgroundColor.contrast(with: NSColor.black.usingColorSpace(NSColorSpace.sRGB)!)
// Contrast of that color with white.
let whiteContrast = backgroundColor.contrast(with: NSColor.white.usingColorSpace(NSColorSpace.sRGB)!)
// Ideal color of the text, based on which has the greater contrast.
let textColor: NSColor = blackContrast > whiteContrast ? .black : .white

在上述情况下,backgroundColor与黑色产生10.595052467245562和白色与0.5045263079640744形成对比。很明显,我们应该使用黑色作为字体颜色!

可以证实here是黑色的值。


编辑.controlTextColor的逻辑将在Apple提供的API的范围之内,而超出我的范围。它与用户的偏好设置等有关,并且可能在运行时对视图进行操作(即,通过设置.controlTextColor,您可能会标记一个视图以检查哪个textColor在运行时更容易识别并应用它)。

TL; DR:我认为您无法通过.controlTextColor子类获得与NSColor相同的效果。

下面是一个子类元素的示例,该元素使用其backgroundColor来确定textColor,以实现相同的效果。根据您对课程应用的backgroundColortextColor将由它决定。

class ContrastTextField: NSTextField {

    override var textColor: NSColor? {
        set {}
        get {
            if let background = self.layer?.backgroundColor {
                let color = NSColor(cgColor: background)!.usingColorSpace(NSColorSpace.sRGB)!
                let blackContrast = color.contrast(with: NSColor.black.usingColorSpace(NSColorSpace.sRGB)!)
                let whiteContrast = color.contrast(with: NSColor.white.usingColorSpace(NSColorSpace.sRGB)!)
                return blackContrast > whiteContrast ? .black : .white
            }
            return NSColor.black
        }
    }

}

然后您可以通过以下方式实现:

let textField = ContrastTextField()
textField.wantsLayer = true
textField.layer?.backgroundColor = NSColor.red.cgColor
textField.stringValue = "test"

将根据textColor的背景来设置layer