I\'m looking for a way to present a UIPickerView
when the user taps on a UIBarButtonItem
. Imagine a filter for the table view results.
I know I
Based on borisgolovnev's suggestion and CodeMonkey's answer, I have implemented the idea with an invisible UITextField
in the following way in Swift 5.
import UIKit
class PickerViewPresenter: UITextField, UIPickerViewDataSource, UIPickerViewDelegate {
private lazy var doneToolbar: UIToolbar = {
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonTapped))
let items = [flexSpace, doneButton]
toolbar.items = items
toolbar.sizeToFit()
return toolbar
}()
private lazy var pickerView: UIPickerView = {
let pickerView = UIPickerView()
pickerView.dataSource = self
pickerView.delegate = self
return pickerView
}()
var items: [Item] = []
var didSelectItem: ((Item) -> Void)?
private var selectedItem: Item?
init() {
super.init(frame: .zero)
setupView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupView() {
inputView = pickerView
inputAccessoryView = doneToolbar
}
@objc private func doneButtonTapped() {
if let selectedItem = selectedItem {
didSelectItem?(selectedItem)
}
resignFirstResponder()
}
func showPicker() {
becomeFirstResponder()
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return items.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return items[row].name
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
selectedItem = items[row]
}
}
Usage in your ViewController:
private var selectedItem: Item?
private lazy var pickerViewPresenter: PickerViewPresenter = {
let pickerViewPresenter = PickerViewPresenter()
pickerViewPresenter.didSelectItem = { [weak self] item in
self?.selectedItem = item
}
return pickerViewPresenter
}()
view.addSubview(pickerViewPresenter)
// e.g. on a button tap
@objc private func buttonTapped() {
pickerViewPresenter.showPicker()
}
Example:
I have attached it to a UITapGestureRecognizer
.