LoginSignup
2
2

More than 3 years have passed since last update.

【iOS】UISegmentedControlの見た目を変える(iOS13対応)

Posted at

概要

UISegmentedControlの見た目を変えたいなぁ - Qiita
さんを参考に、iOS13に対応したカスタムUISegmentedControlを紹介します。

見た目はこんな感じ。
image.png

コード

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

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
FlatSegmentedControlクラスを使うようにします。
image.png
もし、コードでタイトル設定する場合はこのように。

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

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

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

色を変える

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

@IBOutlet weak var flatTab: FlatSegmentedControl! {
    didSet {
        flatTab.setThemeColor(UIColor.cyan)
    }
}

image.png

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2