※ 実装/動作確認環境: Xcode 11 beta5 + Simulator
※※ iOS13正式リリース前につき、スクリーンショットは未掲載(100%見た目についての話なのでなんとも物足りない感じですが…)。
背景
iOS13ではUISegmentedControl
の見た目が変更される。
それに伴い、見た目(主に色)のカスタマイズをする場合、iOS12以前とは異なる方法で行う必要がある。
さしあたりの対応として行ったことをメモ。
(DarkMode対応なども鑑みるとカスタマイズなしで使うようにUIを設計し直すのが妥当とは思うが…)
iOS12以前
tintColor
がビューやラベルの色に適用されるため、ここに任意の色を指定するだけでOKだった。
tintColor = UIColor.orange
iOS13
デフォルトの表示が無彩色となり、tintColor
に依存しなくなった。
以下の方法でそれなりにカスタマイズできる。しかしそれぞれ一長一短あり。
selectedSegmentTintColor
を使用する方法
tintColor
ではなく selectedSegmentTintColor
を指定することで、選択中のセグメントの背景色を設定できる。
また、文字色はデフォルトで黒色であるため、設定する背景色によっては文字色も変更したほうがベター。
func configure() {
let color = UIColor.orange
selectedSegmentTintColor = color
setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], for: .selected)
setTitleTextAttributes([NSAttributedString.Key.foregroundColor: color], for: .normal)
}
メリット
コード量も少なく、やっていることも明確である点。
基本的にはこの程度のカスタマイズで収めたい。
デメリット
この方法ではビューの背景にある薄いグレーはそのままなので、selectedSegmentTintColor
の明度によってはコントラストが弱くなる恐れがある。
(View Hierarchyを確認したところ、SegmentControlのsubview内に半透明のグレー画像が設定されたUIImageViewがある模様)
コントラストに懸念があり、かつ色も変更できない場合は次の方法で薄いグレーの背景を除去するのがよさそう(ただし急場しのぎ。詳細は後述)。
setBackgroundImage()
を使用する方法
func configure() {
let color = UIColor.orange
// 背景を単色画像に差し替え
setBackgroundImage(UIColor.clear.toImage(), for: .normal, barMetrics: .default)
setBackgroundImage(color.toImage(), for: .selected, barMetrics: .default)
// ラベルのスタイルを設定(選択中のセグメントのラベルがBoldでなくなるので、合わせて設定)
setTitleTextAttributes(
[NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 13.0),
NSAttributedString.Key.foregroundColor: UIColor.white],
for: .selected)
setTitleTextAttributes([NSAttributedString.Key.foregroundColor: color], for: .normal)
// グレー領域がなくなったことで境界がわかりづらくなるので、ボーダーを追加
layer.borderColor = color.cgColor
layer.borderWidth = 1.0
}
↑で使用している UIColor.toImage()
は1x1の単色UIImageを生成する拡張メソッド。実装方法はこちらの記事等を参照。
メリット
背景のグレーがなくなるので、SegmentedControlの色をより自由に決められる点。
デメリット
ビューの構造も変わってしまうらしく、見た目はiOS12以前のSegmentedControlのようになってしまう。
また、たかだか6ステップ程度ではあるが、先の方法よりは回りくどい。
そうまでしてiOS12以前っぽい見た目にするのか?となるので、やはりiOS13標準に則ったUIに変更するのが真っ当だと思う。