よくこんなUIPickerViewを見かける。 iOS標準のタイマーに使われているUIPickerViewなのだが、iOS SDKには画像の「hours」「min」のようなラベルを追加する機能がない。
ならば作ってしまえ、というのが今回の記事。
方法としては、UIPickerViewにUILabelを追加する、という単純だがとても汚い方法。 ラベルの位置などハードコーディングになりがちだが、今回は、AutoLayoutにも対応できるよう工夫した。
まずは、UIPickerView, UIPickerViewDataSource, UIPickerViewDelegateを継承したクラスを作成する。
public class PickerLabelView : UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
public required init(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
self.setup()
}
func setup() {
self.delegate = self
self.dataSource = self
}
// UIPickerViewDataSource protocol
public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 3
}
public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return 5
}
// UIPickerViewDelegate protocol
public func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return row.description
}
}
次に、以下のreloadAllComponentLabels関数(名前はなんでもいい)を作成する。
// ラベルの配置
private let labelText = ["hours", "mins", "sec"] // ラベルのテキスト
private var labels :[UILabel] = []
public func reloadAllComponentLabels() {
let fontSize = UIFont.systemFontSize()
let labelTop = self.bounds.origin.y + self.bounds.height / 2 - fontSize // 選択部分のY座標
let labelHeight = self.rowSizeForComponent(0).height // 選択部分の高さ
var labelOffset = self.bounds.origin.x // Componentの右端
// Compoentの数だけ、ラベルを更新
for i in 0...(self.numberOfComponentsInPickerView(self) - 1) {
// ラベルが初期化されていなければ、作成
if self.labels.count == i {
var label = UILabel()
label.text = labelText[i] // テキストを設定
label.backgroundColor = UIColor.clearColor()
label.font = UIFont.boldSystemFontOfSize(fontSize)
label.sizeToFit()
self.addSubview(label)
self.labels.append(label)
}
// ラベルの位置を決める
let labelWidth = self.labels[i].frame.width
labelOffset += self.rowSizeForComponent(i).width
self.labels[i].frame = CGRect(x: labelOffset - labelWidth, y: labelTop, width: labelWidth, height: labelHeight)
}
}
位置決めは、X座標は、Componentの右端座標から文字幅引いたもの、Y座標はUIPickerViewのbounds.heightの半分からフォントサイズを引いたものとなっている。これで大体、どのデバイスでも位置が合う。
最後に、以下のようにlayoutSubviews関数をオーバーライドする。
// レイアウトの変更時にラベルも更新
public override func layoutSubviews() {
super.layoutSubviews()
self.reloadAllComponentLabels()
}
これで綺麗なラベル付きUIPickerViewが完成する。