Skip to content

Instantly share code, notes, and snippets.

@KentarouKanno
Last active May 9, 2022 05:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save KentarouKanno/7352ef8ba0cafefce7c9 to your computer and use it in GitHub Desktop.
Save KentarouKanno/7352ef8ba0cafefce7c9 to your computer and use it in GitHub Desktop.
KeyboardToolBar

KeyBoardToolBar

Github Sample

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        addToolBar(textField: textField)
    }
    
    
    func addToolBar(textField: UITextField) {
        
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black
        let doneButton   = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(ViewController.donePressed))
        let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.cancelPressed))
        let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        
        textField.delegate = self
        textField.inputAccessoryView = toolBar
    }
    
    func donePressed() {
        // Done
        view.endEditing(true)
    }
    
    func cancelPressed() {
        // Cancel
        view.endEditing(true)
    }
}

★ その2 (Doneボタンのみ)

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let toolBar = UIToolbar()
        toolBar.sizeToFit()
        toolBar.barStyle = UIBarStyle.default
        let spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil)
        let commitButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.tapDone))
        toolBar.items = [spacer, commitButton]
        textField.inputAccessoryView = toolBar
    }
    
    @objc func tapDone() {
        view.endEditing(true)
    }
}

★ Extension

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        addToolBar(textField: textField)
    }
}

extension UIViewController: UITextFieldDelegate {
    
    func addToolBar(textField: UITextField) {
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black
        let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(UIViewController.donePressed))
        let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(UIViewController.cancelPressed))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        
        textField.delegate = self
        textField.inputAccessoryView = toolBar
    }
    func donePressed(){
        view.endEditing(true)
    }
    
    func cancelPressed(){
        view.endEditing(true) // or do something
    }
}

★ CustomTextField

import Foundation
import UIKit

/**
 CustomTextFieldDelegate
 */
@objc
protocol CustomTextFieldDelegate: class {
    /**
     Doneボタン押下
     - parameters textField: CustomTextField
     - parameters text: 入力されている文字列
     */
    @objc optional func donePressed(textField: CustomTextField, text: String)
    
    /**
     Cancelボタン押下
     - parameters textField: CustomTextField
     */
    @objc optional func cancelPressed(textField: CustomTextField)
}

/**
 Toolbar付きCustomTextFieldクラス
 */
class CustomTextField: UITextField {
    
    // Delegate
    weak var customTextFieldDelegate: CustomTextFieldDelegate?
    
    /** 
     初期化
    */
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
    }
    
    /// inputAccessoryView
    override var inputAccessoryView: UIView? {
        get {
            
            /// ToolBar
            let toolBar = UIToolbar()
            toolBar.barStyle = .default
            toolBar.isTranslucent = true
            toolBar.tintColor = .black
            
            /// Done Button
            let doneButton = UIBarButtonItem(title: "Done",
                                             style: .done,
                                             target: self,
                                             action: #selector(self.donePressed))
            
            /// Cancel Button
            let cancelButton = UIBarButtonItem(title: "Cancel",
                                               style: .plain,
                                               target: self,
                                               action: #selector(self.cancelPressed))
            
            /// Spacing
            let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                              target: nil,
                                              action: nil)
            
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    /**
     Doneボタン押下時処理
    */
    @objc private func donePressed() {
        if let text = text {
            customTextFieldDelegate?.donePressed?(textField: self, text: text)
        }
        self.resignFirstResponder()
    }
    
    /**
     Cancelボタン押下時処理
    */
    @objc private func cancelPressed() {
        
        customTextFieldDelegate?.cancelPressed?(textField: self)
        self.resignFirstResponder()
    }
}

Image

★ InputViewにDatePickerを使用した場合1
Doneボタンで値を入力

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    
    @IBOutlet weak var textField: UITextField!
    
    let datePicker = UIDatePicker()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        datePicker.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: datePicker.bounds.size.height)
        
        let vi = UIView(frame: datePicker.bounds)
        vi.backgroundColor = UIColor.white
        vi.addSubview(datePicker)
        
        textField.inputView = vi
        datePicker.datePickerMode = .date
        
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black
        let doneButton   = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(self.donePressed))
        let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(self.cancelPressed))
        let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        textField.inputAccessoryView = toolBar
    }
    
    func donePressed() {
        // Done
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd HH:mm"
        let dateStr = formatter.string(from: datePicker.date)
        textField.text = dateStr
        view.endEditing(true)
    }
    
    func cancelPressed() {
        // Cancel
        view.endEditing(true)
    }
}

★ DatePickerTextField

import Foundation
import UIKit

/**
 DatePickerTextFieldDelegate
 */
@objc
protocol DatePickerTextFieldDelegate: class  {
    /**
     Doneボタン押下
     - parameters textField: CustomTextField
     - parameters dateString: yyyyMMddでフォーマットされた文字列(例: 19851128)
     */
    @objc optional func donePressed(textField: DatePickerTextField, dateString: String)
    
    /**
     Cancelボタン押下
     - parameters textField: CustomTextField
     */
    @objc optional func cancelPressed(textField: DatePickerTextField)
}

/**
 Toolbar付きDatePickerTextFieldクラス
 */
class DatePickerTextField: UITextField {
    
    /// Delegate
    weak var datePickerDelegate: DatePickerTextFieldDelegate?
    
    let datePicker = UIDatePicker()
    var datePickerMode: UIDatePickerMode = .date
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.tintColor = .clear
    }
    
    /**
     DatePickerの値を設定、TextFieldの文字も同時に設定
     - parameters dateString: yyyyMMddでフォーマットされた文字列(例: 19851128)
    */
    func setDatePicker(dateString: String) {
        
        // dateString 19851128 → 1985年11月28日
        let formatter: DateFormatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .gregorian)
        formatter.dateFormat = "yyyyMMdd"
        
        if let date = formatter.date(from: dateString) {
            datePicker.date = date
            setTextFieldDateString()
        }
    }
    
    override var inputAccessoryView: UIView? {
        get {
            
            /// ToolBar
            let toolBar = UIToolbar()
            toolBar.barStyle = .default
            toolBar.isTranslucent = true
            toolBar.tintColor = .black
            
            /// Done Button
            let doneButton   = UIBarButtonItem(title: "Done",
                                               style: .done,
                                               target: self,
                                               action: #selector(self.donePressed))
            /// Cancel Button
            let cancelButton = UIBarButtonItem(title: "Cancel",
                                               style: .plain,
                                               target: self,
                                               action: #selector(self.cancelPressed))
            /// Spacing
            let spaceButton  = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                               target: nil,
                                               action: nil)
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    override var inputView: UIView? {
        get {
            /// Create DatePicker
            datePicker.frame = CGRect(x: 0,
                                      y: 44,
                                      width: UIScreen.main.bounds.width,
                                      height: datePicker.bounds.height)
            datePicker.datePickerMode = datePickerMode
            datePicker.backgroundColor = .white
            return datePicker
        }
        set {}
    }
    
    // 入力カーソル非表示
    override func caretRect(for position: UITextPosition) -> CGRect {
        return CGRect.zero
    }
    // 範囲選択カーソル非表示
    override func selectionRects(for range: UITextRange) -> [Any] {
        return []
    }
    
    // コピー・ペースト・選択等のメニュー非表示
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
    
    /**
     テキストフィールドにPickerで選択した文字列を反映する
     */
    func setTextFieldDateString() {
        
        // Format 1985年11月28日
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy年MM月dd日"
        let dateStr = formatter.string(from: datePicker.date)
        self.text = dateStr
    }
    
    /**
     Doneボタン押下時処理
     */
    func donePressed(){
        
        setTextFieldDateString()
        
        // Format 19851128
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyyMMdd"
        let dateStr = formatter.string(from: datePicker.date)
        datePickerDelegate?.donePressed?(textField: self, dateString: dateStr)
        
        self.resignFirstResponder()
    }
    
    /**
     Cancelボタン押下時処理
     */
    func cancelPressed(){
        datePickerDelegate?.cancelPressed?(textField: self)
        self.resignFirstResponder()
    }
}
class DatePickerTextField: UITextField {
    
    let datePicker = UIDatePicker()
    var datePickerMode: UIDatePickerMode = .date
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
    }
    
    override var inputAccessoryView: UIView? {
        get {
            
            let toolBar = UIToolbar()
            toolBar.barStyle = UIBarStyle.default
            toolBar.isTranslucent = true
            toolBar.tintColor = UIColor.black
            let doneButton   = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(self.donePressed))
            let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(self.cancelPressed))
            let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    override var inputView: UIView? {
        get {
            datePicker.frame = CGRect(x: 0, y: 44, width: UIScreen.main.bounds.size.width, height: datePicker.bounds.size.height)
            datePicker.datePickerMode = datePickerMode
            datePicker.backgroundColor = UIColor.white
            return datePicker
        }
        set {}
    }
    
    func donePressed(){
        print("Done!")
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd HH:mm"
        let dateStr = formatter.string(from: datePicker.date)
        self.text = dateStr
        self.resignFirstResponder()
    }
    
    func cancelPressed(){
        print("Cancel!")
        self.resignFirstResponder()
    }
}

★ InputViewにDatePickerを使用した場合2  
Picker切替で値を入力

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    @IBOutlet weak var textField: UITextField!
    let datePicker = UIDatePicker()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        datePicker.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: datePicker.bounds.size.height)
        
        let vi = UIView(frame: datePicker.bounds)
        vi.backgroundColor = UIColor.white
        vi.addSubview(datePicker)
        
        
        textField.inputView = vi
        datePicker.datePickerMode = .date
        datePicker.addTarget(self, action: #selector(self.textFieldEditing(datePicker:)), for: .valueChanged)
        
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black
        let closeButton   = UIBarButtonItem(title: "Close", style: UIBarButtonItemStyle.done, target: self, action: #selector(self.closePressed))
        let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([spaceButton, closeButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        textField.inputAccessoryView = toolBar
    }
    
    func closePressed() {
        // Done
        view.endEditing(true)
    }
    
    func textFieldEditing(datePicker: UIDatePicker) {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd HH:mm"
        let dateStr = formatter.string(from: datePicker.date)
        textField.text = dateStr
    }
}

a

★ InputViewにPickerViewを使用した場合

import UIKit

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    
    @IBOutlet weak var textField: UITextField!
    let pickerView = UIPickerView()
    
    var array = ["楽天", "ソニー", "APPLE", "amazon", "softbank"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pickerView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: pickerView.bounds.size.height)
        pickerView.delegate   = self
        pickerView.dataSource = self
        
        let vi = UIView(frame: pickerView.bounds)
        vi.backgroundColor = UIColor.white
        vi.addSubview(pickerView)
        
        textField.inputView = vi
        
        let toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor.black
        let doneButton   = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(ViewController.donePressed))
        let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.cancelPressed))
        let spaceButton  = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()
        textField.inputAccessoryView = toolBar
    }
    
    // Done
    func donePressed() {
        view.endEditing(true)
    }
    
    // Cancel
    func cancelPressed() {
        textField.text = ""
        view.endEditing(true)
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return array[row]
    }
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return array.count
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        textField.text = array[row]
    }
}

★ PickerTextField
PickerView TextField Sample

import Foundation
import UIKit

/**
 PickerTextFieldDelegate
 */
@objc
protocol PickerTextFieldDelegate: class {
    
    /**
     Doneボタン押下
     - parameters textField: PickerTextField
     - parameters text: 選択した文字列
     */
    @objc optional func donePressed(textField: PickerTextField, text: String)
    
    /**
     Cancelボタン押下
     - parameters textField: PickerTextField
     */
    @objc optional func cancelPressed(textField: PickerTextField)
}

/**
 Toolbar付きPickerTextFieldクラス
 */
class PickerTextField: UITextField, UIPickerViewDelegate, UIPickerViewDataSource {
    
    /// Delegate
    weak var pickerTextFieldDelegate: PickerTextFieldDelegate?
    
    private let pickerView = UIPickerView()
    private let toolbarHeight: CGFloat = 44
    
    /// Pickerに表示する配列
    var pickerDataArray = [String]() {
        didSet {
            if let selectText = pickerDataArray.first {
                self.selectText = selectText
            }
        }
    }
    
    private var selectText: String = ""
    
    /// PickerViewの表示時に選択されている項目を設定する
    var defaultText: String! {
        get { return "" }
        set {
            if let selectIndex = pickerDataArray.index(of: newValue) {
                pickerView.selectRow(selectIndex, inComponent: 0, animated: false)
            } else {
                pickerView.selectRow(0, inComponent: 0, animated: false)
            }
            self.text = newValue
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        self.tintColor = .clear
        pickerView.delegate   = self
        pickerView.dataSource = self
    }
    
    // 入力カーソル非表示
    override func caretRect(for position: UITextPosition) -> CGRect {
        return CGRect.zero
    }
    // 範囲選択カーソル非表示
    override func selectionRects(for range: UITextRange) -> [Any] {
        return []
    }
    
    // コピー・ペースト・選択等のメニュー非表示
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
    
    override var inputAccessoryView: UIView? {
        get {
            
            /// ToolBar
            let toolBar = UIToolbar()
            toolBar.barStyle = UIBarStyle.default
            toolBar.isTranslucent = true
            toolBar.tintColor = UIColor.black
            
            /// Done Button
            let doneButton = UIBarButtonItem(title: "Done",
                                             style: .done,
                                             target: self,
                                             action: #selector(self.donePressed))
            
            /// Cancel Button
            let cancelButton = UIBarButtonItem(title: "Cancel",
                                               style: .plain,
                                               target: self,
                                               action: #selector(self.cancelPressed))
            
            /// Spacing
            let spaceButton  = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                               target: nil,
                                               action: nil)
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    override var inputView: UIView? {
        get {
            
            pickerView.frame = CGRect(x: 0,
                                      y: toolbarHeight,
                                      width: UIScreen.main.bounds.width,
                                      height: pickerView.bounds.height)
            pickerView.backgroundColor = .white
            return pickerView
        }
        set {}
    }
    
    /**
     Doneボタン押下時処理
     */
    @objc private func donePressed() {
        self.text = selectText
        pickerTextFieldDelegate?.donePressed?(textField: self, text: selectText)
        resignFirstResponder()
    }
    
    /**
     Cancelボタン押下時処理
     */
    @objc private func cancelPressed() {
        pickerTextFieldDelegate?.cancelPressed?(textField: self)
        resignFirstResponder()
    }
    
    // MARK: - UIPickerViewDataSource
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerDataArray.count
    }
    
    // MARK: - UIPickerViewDelegate
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return pickerDataArray[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        selectText = pickerDataArray[row]
    }
}

// -------- 使い方 ----------


 import UIKit

class ViewController: UIViewController, UITextFieldDelegate, PickerTextFieldDelegate {
    
    @IBOutlet weak var pickerTextField: PickerTextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        pickerTextField.pickerDataArray = ["😳", "🙍", "🌼", "🌟"]
        pickerTextField.pickerTextFieldDelegate = self
        pickerTextField.delegate = self
    }
    
    // MARK: - UITextFieldDelegate
    
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        pickerTextField.defaultText = pickerTextField.text
        return true
    }
    
    // MARK: - PickerTextFieldDelegate
    
    func pushDoneButton(pickerTextField: PickerTextField, text: String) {
        print(text)
    }
}

★ 2カラムPickerView

import Foundation
import UIKit


/// TwoColumnPickerTextFieldDelegate
@objc
protocol TwoColumnPickerTextFieldDelegate: class {
    
    /**
     Doneボタン押下
     - parameters textField: TwoColumnPickerTextField
     - parameters text:
     */
    @objc optional func donePressed(textField: TwoColumnPickerTextField, text: String)
    
    /**
     Cancelボタン押下
     - parameters textField: TwoColumnPickerTextField
     */
    @objc optional func cancelPressed(textField: TwoColumnPickerTextField)
}


/**
 ToolBar付き2ColumnPickerTextField
 */
class TwoColumnPickerTextField: UITextField, UIPickerViewDelegate, UIPickerViewDataSource {
    
    /// Delegate
    weak var twoColumnPickerDelegate: TwoColumnPickerTextFieldDelegate?
    
    let pickerView = UIPickerView()
    let toolbarHeight: CGFloat = 44
    
    var yearArray = (1940...2017).map{ String($0) }
    var monthArray = (1...12).map{ String($0) }
    
    var selectYear = ""
    var selectMonth = ""
    
    var defaultText: String! {
        get { return "" }
        set(value) {
            
            if value.characters.count == 6 {
                
                let year = value.substring(to: value.index(value.startIndex, offsetBy: 4))
                guard let intMonth = Int(value.substring(from: value.index(value.startIndex, offsetBy: 4))) else {
                    return
                }
                let month = String(intMonth)
                
                if let yearIndex = yearArray.index(of: year),
                    let monthIndex = monthArray.index(of: month) {
                    
                    pickerView.selectRow(yearIndex, inComponent: 0, animated: false)
                    pickerView.selectRow(monthIndex, inComponent: 1, animated: false)
                    
                } else {
                    pickerView.selectRow(0, inComponent: 0, animated: false)
                    pickerView.selectRow(0, inComponent: 1, animated: false)
                }
                selectYear = year
                selectMonth = month
                self.text = year + "" + month + ""
            }
        }
    }
    
    /**
     初期化
    */
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        pickerView.delegate = self
        pickerView.dataSource = self
    }
    
    override var inputAccessoryView: UIView? {
        get {
            
            /// ToolBar
            let toolBar = UIToolbar()
            toolBar.barStyle = .default
            toolBar.isTranslucent = true
            toolBar.tintColor = .black
            
            /// Done Button
            let doneButton   = UIBarButtonItem(title: "Done",
                                               style: .done,
                                               target: self,
                                               action: #selector(self.donePressed))
            
            /// Cancel Button
            let cancelButton = UIBarButtonItem(title: "Cancel",
                                               style: .plain,
                                               target: self,
                                               action: #selector(self.cancelPressed))
            
            /// Spacing
            let spaceButton  = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                               target: nil,
                                               action: nil)
            
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    override var inputView: UIView? {
        get {
            pickerView.frame = CGRect(x: 0,
                                      y: toolbarHeight,
                                      width: UIScreen.main.bounds.width,
                                      height: pickerView.bounds.height)
            pickerView.delegate   = self
            pickerView.dataSource = self
            pickerView.backgroundColor = .white
            return pickerView
        }
        set {}
    }
    
    // 入力カーソル非表示
    override func caretRect(for position: UITextPosition) -> CGRect {
        return CGRect.zero
    }
    // 範囲選択カーソル非表示
    override func selectionRects(for range: UITextRange) -> [Any] {
        return []
    }
    
    // コピー・ペースト・選択等のメニュー非表示
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
    
    /**
     Doneボタン押下時処理
     */
    func donePressed() {
        
        let month = monthArray[pickerView.selectedRow(inComponent: 1)]
        self.text = selectYear + "" + month + ""
        twoColumnPickerDelegate?.donePressed?(textField: self, text: selectYear + selectMonth)
        
        resignFirstResponder()
    }
    
    /**
     Cancelボタン押下時処理
     */
    func cancelPressed() {
        
        twoColumnPickerDelegate?.cancelPressed?(textField: self)
        resignFirstResponder()
    }
    
    // MARK: - UIPickerViewDataSource
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 2
    }
    
    // 表示行
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        switch component {
        case 0 : return yearArray.count
        case 1 : return monthArray.count
        default: return 0
        }
    }
    
    // MARK: - UIPickerViewDelegate
    
    // 各ラベルの幅
    func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
        let screenWidth = UIScreen.main.bounds.size.width
        
        switch component {
        case 0 : return screenWidth / 2
        case 1 : return screenWidth / 2
        default: return 0
        }
    }
    
    //表示内容
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
        case 0 : return yearArray[row] + ""
        case 1 : return monthArray[row] + ""
        default: return nil
        }
    }
    
    //選択時
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch component {
        case 0 : selectYear = yearArray[row]
        case 1 : selectMonth =  String(format: "%02d", Int(monthArray[row]) ?? 1)
        default: break
        }
    }
}

★ CustomTextView(PlaceHolder付き)

import Foundation
import UIKit

/**
 CustomTextViewDelegate
 */
@objc
protocol CustomTextViewDelegate: class {
    /**
     Doneボタン押下
     - parameters textView: CustomTextView
     - parameters text: 入力されている文字列
     */
    @objc optional func donePressed(textView: CustomTextView, text: String)
    
    /**
     Cancelボタン押下
     - parameters textField: CustomTextView
     */
    @objc optional func cancelPressed(textField: CustomTextView)
}

class CustomTextView: UITextView {
    
    /// Delegate
    weak var customTextViewDelegate: CustomTextViewDelegate?
    
    /// placeHolder用のラベル
    lazy var placeHolderLabel:UILabel = UILabel()
    var placeHolderColor:UIColor      = .lightGray
    var placeHolder = ""
    
    /**
     初期化
     */
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        // 文字入力時の通知を登録
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.textChanged(notification:)),
                                               name: NSNotification.Name.UITextViewTextDidChange,
                                               object: nil)
    }
    
    deinit {
        // 通知を解除
        NotificationCenter.default.removeObserver(self)
    }
    
    override public func draw(_ rect: CGRect) {
        
        if self.placeHolder.utf16.count > 0 {
            self.placeHolderLabel.frame = CGRect(x: 8,
                                                 y: 8,
                                                 width: self.bounds.width - 16,
                                                 height: 0)
            
            self.placeHolderLabel.lineBreakMode   = NSLineBreakMode.byWordWrapping
            self.placeHolderLabel.numberOfLines   = 0
            self.placeHolderLabel.font            = self.font
            self.placeHolderLabel.backgroundColor = .clear
            self.placeHolderLabel.textColor       = self.placeHolderColor
            self.placeHolderLabel.alpha           = 0
            self.placeHolderLabel.tag             = 1
            
            self.placeHolderLabel.text = self.placeHolder as String
            self.placeHolderLabel.sizeToFit()
            self.addSubview(placeHolderLabel)
        }
        
        self.sendSubview(toBack: placeHolderLabel)
        textChanged(notification: nil)
        
        super.draw(rect)
    }
    
    public func textChanged(notification:NSNotification?) {
        
        guard placeHolder.utf16.count != 0 else {
            return
        }
        
        // placeHolderの表示、非表示の切り替え
        self.viewWithTag(1)?.alpha = self.text.utf16.count == 0 ? 1 : 0
    }
    
    /// inputAccessoryView
    override var inputAccessoryView: UIView? {
        get {
            
            /// ToolBar
            let toolBar = UIToolbar()
            toolBar.barStyle = .default
            toolBar.isTranslucent = true
            toolBar.tintColor = .black
            
            /// Done Button
            let doneButton = UIBarButtonItem(title: "Done",
                                             style: .done,
                                             target: self,
                                             action: #selector(self.donePressed))
            
            /// Cancel Button
            let cancelButton = UIBarButtonItem(title: "Cancel",
                                               style: .plain,
                                               target: self,
                                               action: #selector(self.cancelPressed))
            
            /// Spacing
            let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
                                              target: nil,
                                              action: nil)
            
            toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
            toolBar.isUserInteractionEnabled = true
            toolBar.sizeToFit()
            
            return toolBar
        }
        set {}
    }
    
    /**
     Doneボタン押下時処理
     */
    @objc private func donePressed() {
        if let text = text {
            customTextViewDelegate?.donePressed?(textView: self, text: text)
        }
        resignFirstResponder()
    }
    
    /**
     Cancelボタン押下時処理
     */
    @objc private func cancelPressed() {
        
        customTextViewDelegate?.cancelPressed?(textField: self)
        self.resignFirstResponder()
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment