-
Notifications
You must be signed in to change notification settings - Fork 2
/
UIColor+colorFromHex.swift
122 lines (90 loc) · 4.63 KB
/
UIColor+colorFromHex.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import UIKit
// An extension to UIColor which adds a class function that returns a UIColor from the provided hex string. The colours are cached.
// Parameters: hexString:String, the hex code for the color you want. Leading "#" is optional. Must be 6 hex digts long. (8 bits per color)
// Usage: let someColor = UIColor.colorFromHex("#2d34aa")
extension UIColor {
// Convert a hex string to a UIColor object.
class func colorFromHex(_ hexString:String) -> UIColor {
func cleanHexString(_ hexString: String) -> String {
var cleanedHexString = String()
// Remove the leading "#"
if(hexString[hexString.startIndex] == "#") {
cleanedHexString = hexString.substring(from: hexString.index(hexString.startIndex, offsetBy: 1))
}
// TODO: Other cleanup. Allow for a "short" hex string, i.e., "#fff"
return cleanedHexString
}
let cleanedHexString = cleanHexString(hexString)
// If we can get a cached version of the colour, get out early.
if let cachedColor = UIColor.getColorFromCache(cleanedHexString) {
return cachedColor
}
// Else create the color, store it in the cache and return.
let scanner = Scanner(string: cleanedHexString)
var value:UInt32 = 0
// We have the hex value, grab the red, green, blue and alpha values.
// Have to pass value by reference, scanner modifies this directly as the result of scanning the hex string. The return value is the success or fail.
if(scanner.scanHexInt32(&value)){
// intValue = 01010101 11110111 11101010 // binary
// intValue = 55 F7 EA // hexadecimal
// r
// 00000000 00000000 01010101 intValue >> 16
// & 00000000 00000000 11111111 mask
// ==========================
// = 00000000 00000000 01010101 red
// r g
// 00000000 01010101 11110111 intValue >> 8
// & 00000000 00000000 11111111 mask
// ==========================
// = 00000000 00000000 11110111 green
// r g b
// 01010101 11110111 11101010 intValue
// & 00000000 00000000 11111111 mask
// ==========================
// = 00000000 00000000 11101010 blue
let intValue = UInt32(value)
let mask:UInt32 = 0xFF
let red = intValue >> 16 & mask
let green = intValue >> 8 & mask
let blue = intValue & mask
// red, green, blue and alpha are currently between 0 and 255
// We want to normalise these values between 0 and 1 to use with UIColor.
let colors:[UInt32] = [red, green, blue]
let normalised = normaliseColors(colors)
let newColor = UIColor(red: normalised[0], green: normalised[1], blue: normalised[2], alpha: 1)
UIColor.storeColorInCache(cleanedHexString, color: newColor)
return newColor
}
// We couldn't get a value from a valid hex string.
else {
print("Error: Couldn't convert the hex string to a number, returning UIColor.whiteColor() instead.")
return UIColor.white
}
}
// Takes an array of colours in the range of 0-255 and returns a value between 0 and 1.
private class func normaliseColors(_ colors: [UInt32]) -> [CGFloat]{
var normalisedVersions = [CGFloat]()
for color in colors{
normalisedVersions.append(CGFloat(color % 256) / 255)
}
return normalisedVersions
}
// Caching
// Store any colours we've gotten before. Colours don't change.
private static var hexColorCache = [String : UIColor]()
private class func getColorFromCache(_ hexString: String) -> UIColor? {
guard let color = UIColor.hexColorCache[hexString] else {
return nil
}
return color
}
private class func storeColorInCache(_ hexString: String, color: UIColor) {
if UIColor.hexColorCache.keys.contains(hexString) {
return // No work to do if it is already there.
}
UIColor.hexColorCache[hexString] = color
}
private class func clearColorCache() {
UIColor.hexColorCache.removeAll()
}
}