はじめに
日付を選択するピッカーが必要になった場合、iOSアプリではUIDatePickerクラスを使えば簡単に作ることができますが、
反面、表示を細かくカスタマイズしたい場合に融通がきかないところがあります。
今回、月と日にちのみを選択するピッカーが必要になったので、UIPickerViewクラスのカスタムクラスを実装して対応しました。
前提条件
- Xcode 8.3.3
- Swift version 3.1
サンプル
ピッカーのイメージ
実装したピッカーのイメージは下記の通りです。
ピッカーのxibファイル
ピッカーのxibファイルの内容は下記画像の通りです。
UIButtonの下にUIPickerViewを配置しています。
実装したカスタムクラス
今回作成したカスタムピッカーのコードは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import UIKit class MonthAndDayPickerView: UIView, UIPickerViewDelegate, UIPickerViewDataSource { @IBOutlet weak var doneButton: UIButton! @IBOutlet weak var pickerView: UIPickerView! let dayOfMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] var monthIndex = 0 init(bounds: CGRect) { let baseWidth = 375.0 let baseHeight = 260.0 let viewRate = Double(bounds.width) / baseWidth let pickerRect = CGRect(x: 0, y: 0, width: baseWidth * viewRate, height: baseHeight * viewRate) super.init(frame: pickerRect) commonInit() } override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } func getMonthAndDay() -> String { let month = "\(pickerView.selectedRow(inComponent: 0) + 1)月" let day = "\(pickerView.selectedRow(inComponent: 1) + 1)日" return month + day } private func commonInit() { let view = Bundle.main.loadNibNamed("MonthAndDayPicker", owner: self, options: nil)?.first as! UIView view.frame = self.bounds view.translatesAutoresizingMaskIntoConstraints = true view.autoresizingMask = .flexibleWidth self.addSubview(view) // Pickerの設定 pickerView.delegate = self } // MARK: - UIPickerView data source func numberOfComponents(in pickerView: UIPickerView) -> Int { return 2 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { switch component { case 0: return dayOfMonth.count case 1: return dayOfMonth[monthIndex] default: return 0 } } // MARK: - UIPickerView delegate func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { if component == 0 { return "\(row + 1)月" } else if component == 1 { return "\(row + 1)日" } else { return nil } } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { if component == 0 { // 選択している月が変わった場合最終日が変わるので、日を再生成する monthIndex = row pickerView.reloadComponent(1) } } } |
呼び出し元のコード
呼び出し元のコードは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import UIKit class ViewController: UIViewController, UITextFieldDelegate { let defaultBirthday = "未設定" var monthAndDayPickerView:MonthAndDayPickerView! @IBOutlet weak var birthdayField: UITextField! func setDatePicker() { monthAndDayPickerView = MonthAndDayPickerView(bounds: self.view.bounds) birthdayField.inputView = monthAndDayPickerView monthAndDayPickerView.doneButton.addTarget( self, action: #selector(ViewController.datePickerSelected), for: UIControlEvents.touchUpInside) } func datePickerSelected() { birthdayField.text = monthAndDayPickerView.getMonthAndDay() view.endEditing(true) } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. birthdayField.text = defaultBirthday birthdayField.delegate = self // DatePickerの生成 setDatePicker() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } |
簡単な解説
MonthAndDayPickerView.swift
3行目:UIPickerViewに関するプロトコルを採用します。
8行目:月ごとに最大日数が異なりますので、1月から12までの各月の日数を定義します。
49〜51行目:ピッカーのコンポーネント数を返します(月と日にちを選択できるので2を返す)
53〜62行目:各コンポーネントの行数を返します。ピッカーが生成されたタイミングとコンポーネントがリロードされたタイミングで実行されます。
66〜74行目:コンポーネントに表示する文字列を返します。
76〜82行目:コンポーネントの値が変化したタイミングで実行されます。月が変更されたタイミングで日にちのコンポーネントをリロードします。
ViewController.swift
12行目:UITextFieldのinputViewにカスタムピッカービューを代入しています。これにより、テキストフィールドをタップした時にピッカーが表示されるようになります。
13〜16行目:カスタムピッカーのDoneボタンにアクションを追加しています。これにより、Doneボタンがタップされた時にdatePickerSelectedメソッドが実行されるようになります。
19〜22行目:Doneボタンがタップされた時にテキストフィールドを更新してピッカーを非表示にします。
さいごに
月と日にちを選択できるUIPickerViewのカスタムクラスを実装しました。
iOSアプリ開発はObjective-Cのシンタックスに違和感を感じることから敬遠していましたが、Swiftのシンタックスはかなり書きやすいと思います。
以前Objective-Cで開発していた方は、この機会にSwiftを初めてみてはいかがでしょうか。