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

3

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

如何获取特定的颜色值?例如,通过调用UIColor.blue.eightDigitsString来获取"#0000FFFF"。

请参见这个链接

5.2. RGB十六进制表示法:#RRGGBB
CSS十六进制颜色表示法使用十六进制数字来指定颜色的通道,类似于在计算机代码中直接编写颜色。它也比使用rgb()表示法更短。
一个十六进制颜色的语法是一个<hash-token>令牌,其值由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相同的颜色。使用3位十六进制语法来指定颜色比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


2
可能是重复的问题:如何将UIColor转换为HEX并在NSLog中显示 - user5306470
@user770 我的意思是,如何获取特定模式的十六进制字符串?(其中之一为“#000”/“#0000”/“#0F0F0F”/“#0000FFFF”)请参见https://drafts.csswg.org/css-color/#hex-notation - Meniny
不要只是链接到文档,而是将相关部分添加到帖子中。 - user5306470
1
“我该如何获取特定的颜色?” - 通过编写代码来获取您想要的内容。没有标准的API可以将UIColor转换为十六进制代码。 - rmaddy
1
@EliasAbel 相反的方式 https://dev59.com/QVwZ5IYBdhLWcg3wJ9jN#31782490 - Leo Dabus
显示剩余7条评论
2个回答

8

这里有一个扩展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

0

任何 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)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接