UIColor または NSColor から RGBA の値を取得

  • 5
    Like
  • 0
    Comment

iOS と Mac でできるだけ多くの共用したコードを使えるようにするために。こんなコードをよく使っています。

#if os(iOS)

import UIKit
typealias XView = UIView
typealias XImage = UIImage
typealias XColor = UIColor
typealias XBezierPath = UIBezierPath
typealias XScrollView = UIScrollView
typealias XViewController = UIViewController

#elseif os(macOS)

import Cocoa
typealias XView = NSView
typealias XImage = NSImage
typealias XColor = NSColor
typealias XBezierPath = NSBezierPath
typealias XScrollView = NSScrollView
typealias XViewController = NSViewController

#endif

すると、以下のように以外と iOS でも mac でも使えるコードが書けたりします。

let bezier = XBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 100, height: 200))
XColor.red.set()
bezier.fill()

UIColor または NSColor から R、G、B、Aの要素を取得したい時に、これを使えば、getRed(_:green:blue:alpha:) で iOS でも macOS でも同様に r, g, b, a の要素を取得できそうですが…

var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
XColor.white.getRed(&r, green: &g, blue: &b, alpha: &a)

iOSでは実際に値が取れるのですが、macOS ではなぜか runtime エラーとなってしまう場合があります。具象クラスはどちらも似たようなものだと思うのですが、iOS と macOS のコードを共用したい場合には障害になります。

macOS
type(of: color) // NSCachedWhiteColor.Type
iOS
type(of: color) // UICachedDeviceWhiteColor.Type

色々調べてみると、CIColor を使うと、r,g,b,a の値が綺麗に取れそうです。そこで、UIColor と NSColor の共通メソッド cgColor を介して、CIColor に変換すると、CIColor のプロパティで RGBA の値を直接取り出せそうです。

CIColor

Screen Shot 2017-01-04 at 0.17.13.png

よって以下のような extension を書いてみました。

#if os(iOS)
import UIKit
#elseif os(macOS)
import Cocoa
#endif

extension XColor {

    var rgba: (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) {
        let color = CIColor(cgColor: self.cgColor)
        return (color.red, color.green, color.blue, color.alpha)
    }

}

これで、iOS でも macOS でも r,g,b,a の値が綺麗に取れるようになりました。

XColor.red.rgba // (1.0, 0.0, 0.0, 1.0)

おまけ

ちなみに、UIBezierPath と NSBezierPath のメソッドも似ているのですが、addLineline のように微妙な違いがあるものもあります。そんな場合は以下のような extension を用意しておけば、どちらのスタイルでも書く事が出来るので便利です。

#if os(macOS)
extension NSBezierPath {

    func addLine(to point: CGPoint) { self.line(to: point) }

}
#endif

#if os(iOS)
extension UIBezierPath {

    func line(to point: CGPoint) { self.addLine(to: point) }

}
#endif

[環境に関する表記]

Xcode Version 8.2.1 (8C1002)
Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)