class TodolistEditViewController: UIViewController {
@IBOutlet weak var categoryTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private func setupView(){
// Picker
let pickerView = UIPickerView()
categoryTextField.inputView = pickerView
let strs = ["カテゴリーなし", "カテゴリー1", "カテゴリー2"]
Observable.just(strs)
.bind(to: pickerView.rx.itemTitles) { _, str in
return str
}.disposed(by: disposeBag)
pickerView.rx.modelSelected(String.self)
.map { strs in
return strs.first
}
.bind(to: categoryTextField.rx.text)
.disposed(by: disposeBag)
// Pickerのヘッダー
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35))
let spacelItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: nil)
toolbar.setItems([spacelItem, doneItem], animated: true)
categoryTextField.inputAccessoryView = toolbar
let doneItemObservable = doneItem.rx.tap.asObservable()
doneItemObservable.subscribe(
onNext: { [weak self] in
// pickerを閉じるには、TextFieldの編集モードを終了させる
self?.categoryTextField.endEditing(true)
}
).disposed(by: disposeBag)
}
}
上記のままでは、テキストフィールドに対してUIPickerView以外からの入力も受け付けてしまう。
そこで、以下の対処を入れる。
class TodolistEditViewController: UIViewController {
private func setupView(){
...
// UIPickerView以外からの入力を拒否するためのdelegate実装
categoryTextField.delegate = self
// 上記だけではカーソルは消えないので、カーソルの色をクリアにする
categoryTextField.tintColor = UIColor.clear
...
}
}
extension TodolistEditViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return false
}
}
ただし、TextFieldを長押しするとcopy/cut/paseteのメニューが表示される。
これを防ぐには、以下のようにカスタムViewにするしか方法がなさそう。
https://riptutorial.com/ja/ios/example/30704/
https://qiita.com/Simmon/items/f9d60ab51cc6b0b4b3bc
■補足1
初期値をUIPickerViewに設定したい場合は以下を追加する
※UITextFieldには自動的に反映される
class TodolistEditViewController: UIViewController {
private func setupView(){
...
let selectedRow = 1
pickerView.selectRow(selectedRow, inComponent: 0, animated: false)
pickerView.delegate?.pickerView!(pickerView,
didSelectRow: selectedRow,
inComponent: 0)
...
}
}
■補足2
UIPickerViewにキャンセルボタンを設定したい場合は以下のように変更する
class TodolistEditViewController: UIViewController {
private let pickerView = UIPickerView()
...
private func setupView(){
...
// カテゴリーPickerのヘッダー
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 35))
let cancelItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: nil)
let spaceItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: nil)
toolbar.setItems([cancelItem,spaceItem, doneItem], animated: true)
categoryTextField.inputAccessoryView = toolbar
// ヘッダーのキャンセルボタン
let cancelItemObservable = cancelItem.rx.tap.asObservable()
cancelItemObservable.subscribe(
onNext: { [weak self] in
// 初期値に戻す
self?.resetCategoryTextField()
// pickerを閉じる
self?.categoryTextField.endEditing(true)
}
).disposed(by: disposeBag)
// ヘッダーの決定ボタン
let doneItemObservable = doneItem.rx.tap.asObservable()
doneItemObservable.subscribe(
onNext: { [weak self] in
// pickerを閉じる
self?.categoryTextField.endEditing(true)
}
).disposed(by: disposeBag)
...
}
private func resetCategoryTextField(){
// ドラムロールを初期値に戻す
// TODO idから動的に取得
let selectedRow = 1
pickerView.selectRow(selectedRow, inComponent: 0, animated: false)
pickerView.delegate?.pickerView!(pickerView,
didSelectRow: selectedRow,
inComponent: 0)
}
}
参考にしたサイト
https://culumn.hatenablog.com/entry/2018/06/07/120000
https://tech.studyplus.co.jp/entry/2018/10/15/114548
http://www.366service.com/jp/qa/d46ff39ee4fe4c17803c9c7affb4495f
https://www.egao-inc.co.jp/programming/swift_uipickerview/
https://grandbig.github.io/blog/2018/10/13/popuppickerview/
https://makotton.com/2016/10/13/1544
https://qiita.com/kazuhiro4949/items/d20f08343937cab82390
https://xyk.hatenablog.com/entry/2014/10/02/105147
https://qiita.com/wai21/items/765206fdc37b2c258481
https://ja.stackoverflow.com/questions/28246/
https://stackoverflow.com/questions/50460554/rxswift-set-initial-value-for-uipickerview