Swift
swift4
PickerView

TextFieldを押下時に下からPickerViewを出すコンポーネント作成をしてみた

概要

一つの画面に複数のpickerViewを定義したい際に、pickerViewのdelegateとdatasourceを定義していくとViewControllerが肥大化してしまうので、TextFieldとPickerViewを継承して、Componentを作成してみました。
※swift初めて間もないので、指摘アドバイスなどあればお願いします。

出来上がり

image.png

ソース

https://github.com/kyosyun/swiftSample/tree/master/PickerSample

構成と役割

image.png

  • ViewController  
    TextFieldPickerViewの呼び出し

  • WeekTextPickerView
    TextFieldとPickerViewの紐付けを実施

  • WeekPickerView  
    pickerの中身の定義を実施。datasorceを定義。

  • TextFieldPickerView
    pickerViewを表示用のToolBarの生成を共通として用意

  • UIViewController
    ToolBarの完了時の動作を一箇所で定義

詳細

ViewController

呼び出しもと

@IBOutlet weak var weekTextField: WeekTextFieldPickerView!

WeekTextPickerView

pickerViewとTextFieldの紐付けを実施

import UIKit

class WeekTextFieldPickerView: TextFieldPickerView {

    //pickerの定義を行う(UIPickerViewを継承したもの)
    let weekPickerView = WeekPickerView()

    //delegateの宣言を行う
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        weekPickerView.weekPickerViewDelegate = self
        self.inputView = weekPickerView.getInputView()
    }
}

extension WeekTextFieldPickerView: WeekPickerViewDelegate {
    //pickerを選択した際の動作 responseに利用する値はここで定義する
    func setValueToTextField(day: String) {
        self.text = day
        self.responseVal = day
    }
}

WeekPickerView

PickerのDatasorceの定義をする。

import UIKit

class WeekPickerView: UIPickerView {

    weak var weekPickerViewDelegate: WeekPickerViewDelegate?

    var week = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]

    init() {
        super.init(frame: CGRect())
        self.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height:self.bounds.size.height)
        self.dataSource = self
        self.delegate = self
        let weekVi = UIView(frame: self.bounds)
        weekVi.backgroundColor = UIColor.white
        weekVi.addSubview(self)
    }

    func getInputView() -> UIView {
        let weekVi = UIView(frame: self.bounds)
        weekVi.backgroundColor = UIColor.white
        weekVi.addSubview(self)
        return weekVi
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

}

extension WeekPickerView: UIPickerViewDelegate {
    //pickerの選択時の動作
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        weekPickerViewDelegate?.setValueToTextField(day: week[row])
    }

}

protocol WeekPickerViewDelegate: class {
    func setValueToTextField(day: String)
}

extension WeekPickerView: UIPickerViewDataSource {

    //pickerのコンポーネント数
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    //pickerの中身の表示
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return week[row]
    }

    //pickerのlistの数
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return week.count
    }
}

TextFieldPickerView

ToolBarの生成。TextFieldの共通のコンポネーントとして生成。
継承して利用する。

import UIKit

class TextFieldPickerView: UITextField {

    var responseVal: String?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.inputAccessoryView = createToolBar()
    }

    func createToolBar() -> UIView {
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black

        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: UIViewController(), action: #selector(
            UIViewController.endiEditing))

        let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)

        toolBar.setItems([spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        return toolBar
    }
}

UIViewController

toolBarの完了ボタン押下時の動作を共通で定義。

import UIKit

extension UIViewController {
    @objc func endiEditing() {
        view.endEditing(true)
    }
}