モチベーション
UIKitを併用していて、Color.gray と、 UIColor.gray で指定した部分で色が異なることに気づきました。
SwiftUIでは、色は、 Color
UIKitでは、 UIColor
と別の型である。
コンソールにprint文出力して確認してもやはり値が異なる。
Gray | 値 |
---|---|
Color | 0x600002ea6b20 |
UIColor | 0x6000030b1170 |
そもそも何故、SwiftUIだけではなく、UIKitを併用しないといけなかった理由は後半に書きます。
ColorのデフォルトはsRGB
Colorの宣言部分をみるとデフォルト引数が sRGBになっていることがわかる。
extension Color {
public enum RGBColorSpace {
case sRGB
case sRGBLinear
case displayP3
...
public init(_ colorSpace: Color.RGBColorSpace = .sRGB, red: Double, green: Double, blue: Double, opacity: Double = 1)
}
}
SwiftUIの色のデフォルトは sRGB指定である。そしてUIColorで指定できる、Generic RGBが選択肢にない。
UIColorで使い方によってRGBの種類が異なるのか?
使用方法 | デフォルト | 例 |
---|---|---|
コード | sRGB | label.backgroundColor = UIColor(red: 245/255.0, green: 84/255.0, blue: 45/255.0, alpha: 1.0) |
Color Literal | sRGB | |
AssetCatalogのColorSet | sRGB |
すべて、sRGBがデフォルトであることがわかる。
Appleの公式を読むと
https://developer.apple.com/documentation/uikit/uicolor
For apps linked against the iOS 9 SDK and earlier, or running on iOS 9 and earlier,
colors use one of two color spaces:
- Device-Dependent Gray
- Device-Dependent RGB
UIColor.gray は iOS9以前から存在したからこれを Generic RGBから sRGBに 色合いを変えることはできなくて取り残されていると考えられる。
みんな大好き16進数色指定extension
今回のようにデフォルトの gray
を使用せずに、 個々で色を指定すると思うが、 せっかくなので、 16進数指定できるものを用意した。 Apple 的には Dark Mode対応のため、AssetCatalog で色指定してほしいのかな?なので使いみちはないかもしれないが一応書いておく。
// MARK: - Helper
extension UIColor {
convenience init(hex: Int, alpha: CGFloat = 1) {
let components = (
R: CGFloat((hex >> 16) & 0xff) / 255,
G: CGFloat((hex >> 08) & 0xff) / 255,
B: CGFloat((hex >> 00) & 0xff) / 255
)
self.init(red: components.R, green: components.G, blue: components.B, alpha: alpha)
}
}
extension Color {
init(hex: Int, alpha: Double = 1) {
let components = (
R: Double((hex >> 16) & 0xff) / 255,
G: Double((hex >> 08) & 0xff) / 255,
B: Double((hex >> 00) & 0xff) / 255
)
self.init(
.sRGB,
red: components.R,
green: components.G,
blue: components.B,
opacity: alpha
)
}
}
使い方
Color(hex: 0xdddddd)
UIColor(hex: 0xdddddd)
ちょっと補足、
UIColorは32bitも使われる時代に作られたものなので、alphaの引数が Doubleではなく、 CGFloatのエイリアスで32bitか64bitかでFloatなのかDoubleなのかを切り替えているが、Colorからは全面的に64bitなので気持ちよくDoubleに振り切っている。(さすがAppleだ)
/// The native type used to store the CGFloat, which is Float on
/// 32-bit architectures and Double on 64-bit architectures.
public typealias NativeType = Double
それとalphaを opacity という単語に変えている。
補足
そもそもなぜアプリ内で UIColorを使おうと思ったかというと
以下の図を見てもらうとわかるように、Listを引っ張った時に、背景が白色で表示されてしまうのを対応するため
initの中で、UITableViewのbackgroundColorを指定するためである。これだけのために、UIKitを指定するのは正直イケていないので、Appleが指定できるIFを用意してくれることを望む(もしSwiftUIで指定する方法をご存じの方がいましたら教えて下さい)
init() {
UITableView.appearance().backgroundColor = UIColor(hex: 0xdddddd)
}
var body: some View {
List(consoleLogs, id: \.self) { value in
Text(value)
.lineLimit(Int.max)
.fixedSize(horizontal: false, vertical: true)
}
}
}
まとめ
ほとんどのアプリではGeneric RGBを使わずにsRGBを使っていて、UIColor.gray みたいなデフォルトの色を使うことはないと思うので実害はないだろう。