【iOS】UISegmentedControlの見た目を変える（iOS13対応）

# 概要
[UISegmentedControlの見た目を変えたいなぁ](https://qiita.com/omotesando/items/b2481cb57fa941adf88c) - Qiita
さんを参考に、iOS13に対応したカスタムUISegmentedControlを紹介します。

見た目はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/1bc5d53a-6777-c9c0-7411-9e57b622357d.png)

# コード
今回書いたカスタムクラスを丸ごと貼ります。
プロジェクト内にコピペしてください。

```swift:FlatSegmentedControl.swift
import UIKit

class FlatSegmentedControl: UISegmentedControl {
    private var segmentItemWidth: CGFloat = 0
    private var underline: CALayer = CALayer()
    private var themeColor: UIColor = UIColor(red: 41/255, green: 171/255, blue: 227/255, alpha: 1)
    private var layers: [CATextLayer] = []

    convenience init() {
        self.init(frame: CGRect.zero)
    }
    
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUp()
    }
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        setUp()
    }

    private func setUp() {
        self.tintColor = UIColor.clear
        underline.backgroundColor = themeColor.cgColor
        self.layer.addSublayer(underline)
        for index in 0 ..< self.numberOfSegments {
            let textLayer = CATextLayer()
            textLayer.string = self.titleForSegment(at: index)
            textLayer.alignmentMode = CATextLayerAlignmentMode.center
            textLayer.contentsScale = UIScreen.main.scale
            textLayer.fontSize = 17
            layers.append(textLayer)
            self.layer.addSublayer(layers[index])
        }
        decorateSelectedItem()
    }

    func setThemeColor(_ color: UIColor) {
        themeColor = color
        underline.backgroundColor = themeColor.cgColor
        rewriteTextLayer()
    }

    override func setTitle(_ title: String?, forSegmentAt segment: Int) {
        super.setTitle(title, forSegmentAt: segment)
        layers[segment].string = title
    }

    private func rewriteTextLayer() {
        for index in 0 ..< self.numberOfSegments {
            let layer = layers[index]
            if index == self.selectedSegmentIndex {
                layer.font = UIFont.boldSystemFont(ofSize: layer.fontSize)
                layer.foregroundColor = themeColor.cgColor
            } else {
                layer.font = UIFont.systemFont(ofSize: layer.fontSize)
                layer.foregroundColor = UIColor.black.cgColor
            }
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        layoutLayerFrame()
    }
    private func decorateSelectedItem() {
        underline.frame.origin.x = CGFloat(self.selectedSegmentIndex) * segmentItemWidth
        rewriteTextLayer()
    }
    private func layoutLayerFrame() {
        segmentItemWidth = self.frame.width / CGFloat(self.numberOfSegments)
        underline.frame = CGRect(x: CGFloat(self.selectedSegmentIndex) * segmentItemWidth, y: self.frame.height - 4, width: segmentItemWidth, height: 4)
        if #available(iOS 13, *) {
            if let defaultLayers = self.layer.sublayers {
                defaultLayers.forEach { (layer) in
                    layer.isHidden = true
                }
            }
            layer.cornerRadius = 0
        }
        for index in 0 ..< self.numberOfSegments {
            layers[index].frame = CGRect(x: segmentItemWidth * CGFloat(index), y: 8, width: segmentItemWidth, height: self.frame.height - 12)
            if #available(iOS 13, *) { layers[index].isHidden = false }
        }
        if #available(iOS 13, *) { underline.isHidden = false }
        decorateSelectedItem()
    }
}
```

# 使い方
## 基本
Storyboardの例で進めます。

UISegmentedControlを選んで設置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/83acb1df-8d04-172e-ceaf-3af516973f18.png)
FlatSegmentedControlクラスを使うようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/061a4953-ba86-3b85-210f-3adbf4bef3c1.png)
もし、コードでタイトル設定する場合はこのように。

```swift
    @IBOutlet weak var flatTab: FlatSegmentedControl! {
        didSet {
            flatTab.setTitle("1番目タブ", forSegmentAt: 0)
            flatTab.setTitle("2番目タブ", forSegmentAt: 1)
            flatTab.setTitle("3番目タブ", forSegmentAt: 2)
        }
    }
```

Actionにはタブ選択時の動作を書きます。これもUISegmentedControlと同じ。

```swift
    @IBAction func onTabTap(_ sender: FlatSegmentedControl) {
        switch sender.selectedSegmentIndex {
        case 0:
            // 1番目が選択された時にすること
        case 1:
            // 2番目が選択された時にすること
        case 2:
            // 3番目が選択された時にすること
        default:
            // デフォルト挙動
        }
    }
```

## 色を変える
`setThemeColor`というメソッドを生やしてあるので、このようにUIColorを渡してください。

```swift
@IBOutlet weak var flatTab: FlatSegmentedControl! {
    didSet {
        flatTab.setThemeColor(UIColor.cyan)
    }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272677/d02ac823-05c4-e94a-cbc7-9fa163242ad3.png)