如何在 Swift 中将 UIColor 转换为 3/4/6/8 位十六进制字符串?



如何在 Swift 中将 UIColor 转换为 3/4/6/8 位的十六进制字符串?

我如何获得一个壮观的? 例如,通过调用UIColor.blue.eightDigitsString来获取"#0000FFFF">

请看这个:

5.2. RGB 十六进制表示法:#RRGGBB

CSS 十六进制颜色表示法允许通过将通道作为十六进制数字来指定颜色,这类似于通常直接在计算机代码中编写颜色的方式。它也比用 rgb(( 表示法写出相同的颜色要短。

a 的语法是一个<哈希令牌>令牌,其值由 3、4、6 或 8 个十六进制数字组成。换句话说,十六进制颜色写成哈希字符"#",后跟一定数量的数字 0-9 或字母 a-f(字母的大小写无关紧要 - #00ff00 与 #00FF00 相同(。

给出的十六进制数字的数量决定了如何将十六进制表示法解码为 RGB 颜色:

6 位数字
第一对数字(解释为十六进制数字(指定颜色的红色通道,其中 00 表示最小值,ff(十进制为 255(表示最大值。下一组数字以相同的方式解释,指定绿色通道,最后一对指定蓝色通道。颜色的 alpha 通道是完全不透明的。 换句话说,#00ff00 表示与 rgb(0 255 0((柠檬绿(相同的颜色。

8 位数字 前 6 位
数字的解释与 6 位表示法相同。最后一对数字(解释为十六进制数(指定颜色的 alpha 通道,其中 00 表示完全透明的颜色,ff 表示完全不透明的颜色。 换句话说,#0000ffcc 表示与 rgb(0 0 100%/80%((略微透明的蓝色(相同的颜色。

3 位
数字 这是 6 位表示法的较短变体。第一个数字被解释为十六进制数,指定颜色的红色通道,其中 0 表示最小值,f 表示最大值。接下来的两个数字分别以相同的方式表示绿色和蓝色通道。颜色的 alpha 通道是完全不透明的。 这种语法通常通过说它与通过"复制"所有数字获得的 6 位表示法相同来解释。例如,表示法 #123 指定的颜色与表示法 #112233 相同。这种指定颜色的方法的"分辨率"低于 6 位表示法;在 3 位十六进制语法中只有 4096 种可能的颜色可以表达,而在 6 位十六进制语法中大约有 1700 万种颜色。

4 位
数字 这是 8 位表示法的较短变体,"扩展"的方式与 3 位表示法相同。第一个数字被解释为十六进制数,指定颜色的红色通道,其中 0 表示最小值,f 表示最大值。接下来的三位数字分别表示绿色、蓝色和 Alpha 通道。

现在我已经知道如何将UIColor对象转换为 6 位十六进制字符串。但我不确定如何将其转换为 3 位/4 位/8 位十六进制字符串以及应该注意什么。

guard let components = cgColor.components, components.count >= 3 else {
return nil
}
let r = Float(components[0])
let g = Float(components[1])
let b = Float(components[2])
var a = Float(1.0)
if components.count >= 4 {
a = Float(components[3])
}
if alpha {
// rrggbbaa mode
// is there any difference between rrggbbaa and aarrggbb?
return String(format: "%02lX%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255), lroundf(a * 255))
} else {
// rrggbb mode
return String(format: "%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255))
}

注意:字符串UIColor,字符串UIColor

下面是UIColor的扩展,可以提供多种格式的十六进制字符串,包括 3、4、6 和 8 位形式:

extension UIColor {
enum HexFormat {
case RGB
case ARGB
case RGBA
case RRGGBB
case AARRGGBB
case RRGGBBAA
}
enum HexDigits {
case d3, d4, d6, d8
}
func hexString(_ format: HexFormat = .RRGGBBAA) -> String {
let maxi = [.RGB, .ARGB, .RGBA].contains(format) ? 16 : 256
func toI(_ f: CGFloat) -> Int {
return min(maxi - 1, Int(CGFloat(maxi) * f))
}
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
self.getRed(&r, green: &g, blue: &b, alpha: &a)
let ri = toI(r)
let gi = toI(g)
let bi = toI(b)
let ai = toI(a)
switch format {
case .RGB:       return String(format: "#%X%X%X", ri, gi, bi)
case .ARGB:      return String(format: "#%X%X%X%X", ai, ri, gi, bi)
case .RGBA:      return String(format: "#%X%X%X%X", ri, gi, bi, ai)
case .RRGGBB:    return String(format: "#%02X%02X%02X", ri, gi, bi)
case .AARRGGBB:  return String(format: "#%02X%02X%02X%02X", ai, ri, gi, bi)
case .RRGGBBAA:  return String(format: "#%02X%02X%02X%02X", ri, gi, bi, ai)
}
}
func hexString(_ digits: HexDigits) -> String {
switch digits {
case .d3: return hexString(.RGB)
case .d4: return hexString(.RGBA)
case .d6: return hexString(.RRGGBB)
case .d8: return hexString(.RRGGBBAA)
}
}
}

例子

print(UIColor.red.hexString(.d3))  // #F00
print(UIColor.red.hexString(.d4))  // #F00F
print(UIColor.red.hexString(.d6))  // #FF0000
print(UIColor.red.hexString(.d8))  // #FF0000FF
print(UIColor.green.hexString(.RGB))  // #0F0
print(UIColor.green.hexString(.ARGB))  // #F0F0
print(UIColor.green.hexString(.RGBA))  // #0F0F
print(UIColor.green.hexString(.RRGGBB))  // #00FF00
print(UIColor.green.hexString(.AARRGGBB))  // #FF00FF00
print(UIColor.green.hexString(.RRGGBBAA))  // #00FF00FF
print(UIColor(red: 0.25, green: 0.5, blue: 0.75, alpha: 0.3333).hexString()) // #4080c055

任何UIColor实例都可以用 8 个十六进制数字表示:例如#336699CC.对于某些颜色,可以使用较短的表示形式:

  • 对于不透明颜色(未指定 Alpha 或 1.0(,可以省略 Alpha 组件:#336699FF变为#336699
  • 如果所有颜色分量都由同一数字对组成,则只需指定一次数字:#336699CC变为#369C,但#335799CC不能缩短
  • 上述两个规则可以组合使用:#336699FF变得#369

以下函数将返回给定UIColor允许的最短有效表示形式。

struct HexRepresentationOptions: OptionSet {
let rawValue: UInt
static let allowImplicitAlpha = HexRepresentationOptions(rawValue: 1 << 0)
static let allowShortForm = HexRepresentationOptions(rawValue: 1 << 1)
static let allowAll: HexRepresentationOptions = [
.allowImplicitAlpha, 
.allowShortForm
]
}
func hexRepresentation(forColor color: UIColor, 
options: HexRepresentationOptions = .allowAll) -> String? {
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
var alpha: CGFloat = 0.0
guard color.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
return nil
}
let colorComponents: [CGFloat]
if options.contains(.allowImplicitAlpha) && alpha == 1.0 {
colorComponents = [red, green, blue]
} else {
colorComponents = [red, green, blue, alpha]
}
let hexComponents = colorComponents.map { component -> (UInt8, UInt8, UInt8) in
let hex = UInt8(component * 0xFF)
return (hex, hex & 0x0F, hex >> 4)
}
let hasAlpha = colorComponents.count == 4
let useShortForm = options.contains(.allowShortForm) && 
!hexComponents.contains(where: { c in c.1 != c.2 })
let hexColor: UInt64 = hexComponents.reduce(UInt64(0)) { result, component in
if useShortForm {
return (result << 4) | UInt64(component.1)
} else {
return (result << 8) | UInt64(component.0)
}
}
switch (useShortForm, hasAlpha) {
case (true, false):
return String(format: "#%03X", hexColor)
case (true, true):
return String(format: "#%04X", hexColor)
case (false, false):
return String(format: "#%06X", hexColor)
case (false, true):
return String(format: "#%08X", hexColor)
}
}

最新更新