[Swift] UIColorをWeb カラーで指定する


Web系のMacにあんまり詳しくないデザイナーさんと仕事をするときに、色指定がwebカラーで#XXXXXX指定されることがあります。

計算違いなどがめんどくさいので、できれば、その色指定をそのままコードに書き込みたいみたいなときには、Swiftのextensionを使ってUIカラーのイニシャライザを作ってしまうのが便利かもしれません。「#ABCDEF」を正規表現で、「AB」「CD」「EF」を取り出して、CGFloatでその値を0から1.0までの値で指定するイニシャライザを、extensionで拡張すれば簡単にできそうです。

正規表現で文字列をArrayに分離する

StackOverflowに、Stringを拡張して正規表現でArrayを作る方法 が載っています。

Extensions.swift
/*
    Swift extract regex matches
    mitchkman asked Jan 10 '15 at 20:04
    Martin R. answered Jan 10 '15 at 20:12
    https://stackoverflow.com/questions/27880650/swift-extract-regex-matches

    mitchkman
    https://stackoverflow.com/users/1867854/mitchkman
    Martin R.
    https://stackoverflow.com/users/1187415/martin-r
 */
extension String {
    func matchingStrings(regex: String) -> [[String]] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
        let nsString = self as NSString
        let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
        return results.map { result in
            (0..<result.numberOfRanges).map {
                result.range(at: $0).location != NSNotFound
                    ? nsString.substring(with: result.range(at: $0))
                    : ""
            }
        }
    }
}

これを使ってUIColorの拡張を作る方法を考えました。

UIColorのイニシャライザを拡張する

私はSwift標準のクラスを拡張するクラスをまとめて、Extensions.swiftを用意しているので、そこに以下を書き足します。

Extension.swift
extension UIColor {
    convenience init(webcolor: String) {
        let colorsArray  = webcolor.matchingStrings(regex: "#(..)(..)(..)")
        let r = Double(Int(colorsArray[0][1], radix: 16)!) / 255.0
        let g = Double(Int(colorsArray[0][2], radix: 16)!) / 255.0
        let b = Double(Int(colorsArray[0][3], radix: 16)!) / 255.0
        self.init(displayP3Red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: CGFloat(1.0))
    }
}

こうすれば、

ViewController.swift
button.backgroundColor =  UIColor(webcolor: "#ffbbcc")

みたいなことができます。

プロジェクトカラー拡張

さらにデザイナーさんによっては、プロダクトのキーカラーを、カラーセットとして、以下のサイトのように決めてくることがあります。

このカラーセットのテーマをコードに埋め込んでしまうことも可能です。

Extension.swift
    enum ProjectColors {
        case Mist
        case Stone
        case Shadow
        case AutumnFolige
    }

    convenience init(themeColor: ProjectColors) {
        if (themeColor == .Mist) {
            self.init(webcolor: "#90AFC5")
            return
        }
        if (themeColor == .Stone) {
            self.init(webcolor: "#336b87")
            return
        }
        if (themeColor == .Shadow) {
            self.init(webcolor: "#2A3132")
            return
        }
        self.init(webcolor: "#763626")
    }
}

こういうふうに拡張すれば、以下のように呼び出すことも可能です。

UIViewController.swift
button.backgroundColor =  UIColor(themeColor: .Mist)

そりゃあ、AssetCatalogでデザイナーさんが名前付きの色を、現場のプログラマまで供給してくれるのが、もちろん一番楽ではあります。参考:https://qiita.com/shira-shun/items/281e583f1aa0fc446b87

ですが、それはデザイナーさんもiOSプログラマだった場合だけ。圧倒的にWeb系デザイナさんのほうが多いわけですから、プログラマ側が工夫しておくのも一つ良い方法だとは思っています。

ちなみに、あえて文字列でやっている理由は、jsonと組み合わせて使うことも、見越して、です。