環境
- Xcode 11.3
何が起こったのか
いつもどおり 0.5 の線を引くために Storyboard の AutoLayout で Height = 0.5
の制約を指定した。
すると、デザイナーから「線の太さにばらつきがあるので揃えてほしい」と指摘があった。
↑たしかによく見ると上の線のほうが若干濃くも見える・・。両方とも 0.5 で指定しているが、念のため次のコードを書いて height を出力してみた。
print(separator1.frame.size.height) // 上の線
print(separator2.frame.size.height) // 下の線
すると、
0.66666666666666
0.33333333333333
と出力された!
目の錯覚ではなく、たしかに上の線のほうが濃いことがわかった。
なぜ0.5で指定しているのに正しく描画されないか
Twitter にてこの疑問をつぶやいてみたところ、 @kishikawakatsumi さんが回答をくださった。
Frameの小数部分は実行時にPixel alignedになるように丸められるからですね。Scaleをかけて割る、みたいな処理が自動的に入ってます。
https://twitter.com/k_katsumi/status/1224279359529205760
なるほど!
つまり、iPhone 11 Pro のような x3 でレンダリングされるデバイスは 1pt の線が実際には 3px で描画される。pxに小数を含むことはできないため、小数点以下は丸められてしまう。
例)0.5pt で指定された線は1.5pxで描画しようとするが、小数点が丸められ、1px(=0.3333pt)か2px(=0.6666pt)として描画される。
このとき、どう丸められるかはコントロールできない。 このため、太さに差が出てしまっていた!
参考:x2 や x3 についてはこのデバイス一覧表がわかりやすい
https://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
どうしたらよいか
やはり同じ悩みを持っている人がいた。
ios - How to create a line width of 0.5 pixels - Stack Overflow
つまり、
- x3 デバイスでは 0.3 pt で指定するようにする
- x2 デバイスでは 0.5 pt で指定するようにする
このようにすると、確かにどのデバイスでもばらつきがなく線画描画されるようになった。
しかし、 Storyboard では 0.5 単位でしか height を指定できなので、次のようなコードを書いて線を実装する必要がありそう。
(1.0 / [UIScreen mainScreen].scale)
2020/2/4 追記:
1 / scaleの高さを制約に設定したSeparatorというCustom Viewを作る方法もあるそうです!@IBDesignable
にしておくとStoryboardに置くだけで使える
https://twitter.com/k_katsumi/status/1224503484822671360
なにかおかしなことを書いていたらコメントお願いします