简体   繁体   English

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

[英]How do I convert a UIColor to a 3/4/6/8 digits hexadecimal string in Swift?

How do I convert a UIColor to a hexadecimal string of 3/4/6/8 digits in Swift? 如何在Swift中将UIColor转换为3/4/6/8位数的十六进制字符串?

How do I get a spectific one? 我如何获得一个特定的? for example, get "#0000FFFF" by calling UIColor.blue.eightDigitsString 例如,通过调用UIColor.blue.eightDigitsString获得“#0000FFFF”

Please See this : 请看这个

5.2. 5.2。 The RGB hexadecimal notations: #RRGGBB RGB十六进制表示法:#RRGGBB

The CSS hex color notation allows a color to be specified by giving the channels as hexadecimal numbers, which is similar to how colors are often written directly in computer code. CSS十六进制颜色表示法通过将通道指定为十六进制数字来指定颜色,这类似于通常直接在计算机代码中编写颜色的方式。 It's also shorter than writing the same color out in rgb() notation. 它比用rgb()表示法写相同的颜色还短。

The syntax of a is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits. a的语法是<hash-token>令牌,其值由3、4、6或8个十六进制数字组成。 In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or letters af (the case of the letters doesn't matter - #00ff00 is identical to #00FF00). 换句话说,十六进制颜色被写为哈希字符“#”,后跟一些数字0-9或字母af(字母大小写无关紧要-#00ff00与#00FF00相同)。

The number of hex digits given determines how to decode the hex notation into an RGB color: 给定的十六进制数字的数量决定了如何将十六进制表示法解码为RGB颜色:

6 digits 6位数
The first pair of digits, interpreted as a hexadecimal number, specifies the red channel of the color, where 00 represents the minimum value and ff (255 in decimal) represents the maximum. 第一对数字(解释为十六进制数字)指定颜色的红色通道,其中00表示最小值,ff(十进制255)表示最大值。 The next pair of digits, interpreted in the same way, specifies the green channel, and the last pair specifies the blue. 以相同方式解释的下一对数字指定绿色通道,最后一对数字指定蓝色通道。 The alpha channel of the color is fully opaque. 颜色的Alpha通道是完全不透明的。 In other words, #00ff00 represents the same color as rgb(0 255 0) (a lime green). 换句话说,#00ff00表示与rgb(0 255 0)相同的颜色(柠檬绿)。

8 digits 8位数字
The first 6 digits are interpreted identically to the 6-digit notation. 前6位数字与6位数字符号的解释相同。 The last pair of digits, interpreted as a hexadecimal number, specifies the alpha channel of the color, where 00 represents a fully transparent color and ff represent a fully opaque color. 最后一对数字(解释为十六进制数字)指定颜色的Alpha通道,其中00表示完全透明的颜色,ff表示完全不透明的颜色。 In other words, #0000ffcc represents the same color as rgb(0 0 100% / 80%) (a slightly-transparent blue). 换句话说,#0000ffcc表示与rgb(0 0 100%/ 80%)(略透明的蓝色)相同的颜色。

3 digits 3位数
This is a shorter variant of the 6-digit notation. 这是6位数符号的缩写。 The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. 第一位解释为十六进制数字,指定该颜色的红色通道,其中0表示最小值,f表示最大值。 The next two digits represent the green and blue channels, respectively, in the same way. 接下来的两位数字以相同的方式分别代表绿色和蓝色通道。 The alpha channel of the color is fully opaque. 颜色的Alpha通道是完全不透明的。 This syntax is often explained by saying that it's identical to a 6-digit notation obtained by "duplicating" all of the digits. 通常通过说它与通过“复制”所有数字获得的6位数字表示法相同来解释该语法。 For example, the notation #123 specifies the same color as the notation #112233. 例如,符号#123指定与符号#112233相同的颜色。 This method of specifying a color has lower "resolution" than the 6-digit notation; 这种指定颜色的方法的“分辨率”低于6位数字的表示法。 there are only 4096 possible colors expressible in the 3-digit hex syntax, as opposed to approximately 17 million in 6-digit hex syntax. 3位十六进制语法中只能显示4096种可能的颜色,而6位十六进制语法中大约有1,700万种颜色。

4 digits 4位数
This is a shorter variant of the 8-digit notation, "expanded" in the same way as the 3-digit notation is. 这是8位数字表示法的较短变体,以与3位数字表示法相同的方式“扩展”。 The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. 第一位解释为十六进制数字,指定该颜色的红色通道,其中0表示最小值,f表示最大值。 The next three digits represent the green, blue, and alpha channels, respectively. 接下来的三个数字分别代表绿色,蓝色和Alpha通道。

Now I already know how to convert a UIColor object to a 6-digits hex string. 现在,我已经知道如何将UIColor对象转换为6位十六进制字符串。 But I'm not sure how to convert it to a 3-digits/4-digits/8-digits hex string and what should be noticed. 但是我不确定如何将其转换为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))
}

NOTE: it's UIColor to string, not string to UIColor 注意:它是字符串的UIColor ,而不是UIColor字符串

Here's an extension for UIColor that can provide hexStrings in many formats including 3, 4, 6, and 8 digit forms: 这是UIColor的扩展,可以提供多种格式的hexString,包括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)
        }
    }
}

Examples 例子

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

Any UIColor instance can be represented by 8 hexadecimal digits: for example #336699CC . 任何UIColor实例都可以由8个十六进制数字表示:例如#336699CC For some colours, a shorter representation can be used: 对于某些颜色,可以使用较短的表示形式:

  • for opaque colours (alpha unspecified or 1.0), the alpha component can be left off: #336699FF becomes #336699 对于不透明的颜色(未指定alpha或1.0),可以保留alpha分量: #336699FF变为#336699
  • if all colour components consist of pairs of the same digit, the digit only needs to be specified once: #336699CC becomes #369C , but #335799CC cannot be shortened 如果所有颜色分量均由相同数字对组成,则仅需指定一次该数字: #336699CC变为#369C ,但#335799CC无法缩短
  • the two rules above can be combined: #336699FF becomes #369 可以将以上两个规则结合起来: #336699FF变为#369

The following function will return the shortest valid representation allowed for a given UIColor . 以下函数将返回给定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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM