Edited at

iOS13でUISegmentedControlの見た目をカスタマイズする

※ 実装/動作確認環境: 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に変更するのが真っ当だと思う。


参考