Если вы хотите передать любой цвет, а затем определить, какой цвет текста будет более идеальным - черный или белый - вам сначала нужно определить яркость этого цвета (в 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
с белым.Ясно, что мы должны использовать черный в качестве цвета шрифта!
Значение черного можно подтвердить здесь .
РЕДАКТИРОВАТЬ: Логика для .controlTextColor
будет лежать под поверхностью API, предоставляемого Apple, и вне меня.Он связан с предпочтениями пользователя и т. Д. И может работать с представлениями во время выполнения (т. Е. Установив .controlTextColor
, вы можете пометить представление, чтобы проверить, какой из них textColor
более разборчиво во время выполнения, и применить его).
TL; DR: я не думаю, что у вас есть возможность достичь того же эффекта, что и .controlTextColor
с подклассом NSColor
.
Вот примерподклассный элемент, который использует backgroundColor
для определения textColor
, однако для достижения того же эффекта.В зависимости от того, backgroundColor
вы применяете к классу, textColor
будет определяться им.
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
.