概要
UISegmentedControlの見た目を変えたいなぁ - Qiita
さんを参考に、iOS13に対応したカスタムUISegmentedControlを紹介します。
コード
今回書いたカスタムクラスを丸ごと貼ります。
プロジェクト内にコピペしてください。
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を選んで設置します。
FlatSegmentedControlクラスを使うようにします。
もし、コードでタイトル設定する場合はこのように。
@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)
}
}