LoginSignup
6
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-01-03

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)
6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4