像键盘一样显示UIPickerView,没有UITextField

leo*_*ato 11 uikit ios ios6

我正在寻找一种方法来呈现UIPickerView用户点击的时间UIBarButtonItem.想象一下表格视图结果的过滤器.

我知道我可以使用UITextFieldinputView,但事实并非如此 - 我只有a UIBarButtonItem和a UITableView.

我已经看过使用UIActionSheet,但它看起来并不自然,特别是当它显示动画时.

UIView手动启动和关闭屏幕动画是唯一的选择吗?

该应用程序仅适用于iOS 6+和iPhone,因此我无需与任何其他版本/习语保持兼容.

Mic*_*son 20

将UIPickerView作为已添加到视图中的0大小的UITextField的inputView附加.

        let picker = UIPickerView()
        picker.dataSource = self
        picker.delegate = self

        let dummy = UITextField(frame: CGRectZero)
        view.addSubview(dummy)

        dummy.inputView = picker
        dummy.becomeFirstResponder()
Run Code Online (Sandbox Code Playgroud)

  • 对于 swift3,在 let dummy = UITextField(frame: CGRect.zero) 中使用 CGRect.zero (3认同)

bor*_*nev 7

一个更好的选择仍然是使用UITextField.您不必在屏幕上实际显示它.只需将它放在0x0 UIView中就可以看到它,将它设置inputView为你的UIPickerView并调用becomeFirstResponder它来显示选择器并resignFirstResponder隐藏它.

为方便起见,有一个UIView实现所有的与沿子类UIPickerViewDelegateUIPickerViewDataSource方法.


Gle*_*enn 7

至少对我来说最干净的方式,对于Swift4 + Autolayout解决方案,没有a UITextField是添加一个UIView作为顶视图/按钮的容器UIPickerView和a UIToolbar.

然后,如果需要,可以使用动画切换该容器视图的插入/偏移,以隐藏和取消隐藏选择器.

性能

private lazy var view_PickerContainer: UIView = {
    let view = UIView()
    view.backgroundColor = .white
    view.addSubview(self.timePicker)
    view.addSubview(self.toolbar_Picker)
    return view
}()

private lazy var timePicker: UIDatePicker = {
    let picker = UIDatePicker()
    picker.minimumDate = Date()
    picker.datePickerMode = .time
    picker.setDate(Date(), animated: true)
    return picker
}()

private let timeFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "hh:mm a"
    return formatter
}()

private lazy var toolbar_Picker: UIToolbar = {
    let toolbar = UIToolbar()
    toolbar.barStyle = .blackTranslucent
    toolbar.barTintColor = .blueDarkText
    toolbar.tintColor = .white
    self.embedButtons(toolbar)
    return toolbar
}()
Run Code Online (Sandbox Code Playgroud)

我用来SnapKit以编程方式布局我的视图.您可以使用timePicker's bounds.size作为布局的参考.

实施

在viewDidLoad()中

    // Setup timepicker and its container.
    self.view.addSubview(self.view_PickerContainer)
    self.view_PickerContainer.snp.makeConstraints { (make) in
        make.height.equalTo(self.timePicker.bounds.size.height + 50.0)
        make.leading.trailing.equalToSuperview()
        self.constraint_PickerContainerBottom = make.bottom.equalToSuperview().inset(-500.0).constraint
    }

    self.timePicker.snp.makeConstraints { (make) in
        make.height.equalTo(self.timePicker.bounds.size.height)
        make.width.equalToSuperview()
        make.bottom.equalToSuperview()
    }

    // Add toolbar for buttons.
    self.toolbar_Picker.snp.makeConstraints { (make) in
        make.height.equalTo(40.0)
        make.top.leading.trailing.equalToSuperview()
    }
Run Code Online (Sandbox Code Playgroud)

嵌入顶视图

private func embedButtons(_ toolbar: UIToolbar) {
    func setupLabelBarButtonItem() -> UIBarButtonItem {
        let label = UILabel()
        label.text = "Set Alarm Time"
        label.textColor = .white
        return UIBarButtonItem(customView: label)
    }

    let todayButton = UIBarButtonItem(title: "Today", style: .plain, target: self, action: #selector(self.todayPressed(_:)))

    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.donePressed(_:)))

    let flexButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)

    toolbar.setItems([todayButton, flexButton, setupLabelBarButtonItem(), flexButton, doneButton], animated: true)
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述


Cod*_*key 6

我选择了borisgolovnev建议的隐形,UITextField并提出了以下Swift 2.3实现:

import UIKit

class PickerViewPresenter: UITextField {

    // MARK: - Initialization

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    init() {
        super.init(frame: CGRect.zero)
    inputView = pickerView
    inputAccessoryView = pickerInputAccessoryView
    }

    // MARK: - Public

    var pickerDelegate: UIPickerViewDelegate? {
        didSet {
            pickerView.delegate = pickerDelegate
        }
    }

    var pickerDataSource: UIPickerViewDataSource? {
        didSet {
            pickerView.dataSource = pickerDataSource
        }
    }

    var selectButtonAction: (() -> Void)?

    var currentlySelectedRow: Int {
        return pickerView.selectedRowInComponent(0)
    }

    func selectRowAtIndex(index: Int) {
        pickerView.selectRow(index, inComponent: 0, animated: false)
    }

    func showPicker() {
        self.becomeFirstResponder()
    }

    func hidePicker() {
        self.resignFirstResponder()
    }

    // MARK: - Views

    private let pickerView = UIPickerView(frame: CGRect.zero)

    private lazy var pickerInputAccessoryView: UIView = {
        let frame = CGRect(x: 0.0, y: 0.0, width: 0.0, height: 48.0)
        let pickerInputAccessoryView = UIView(frame: frame)

        // Customize the view here

        return pickerInputAccessoryView
    }()

    func selectButtonPressed(sender: UIButton) {
        selectButtonAction?()
    }

}
Run Code Online (Sandbox Code Playgroud)

然后可以方便地使用PickerViewPresenter:

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(pickerViewPresenter)
    }

    private let dataModel = [10, 20, 30, 40, 50]

    private lazy var pickerViewPresenter: PickerViewPresenter = {
        let pickerViewPresenter = PickerViewPresenter()
        pickerViewPresenter.pickerDelegate = self
        pickerViewPresenter.pickerDataSource = self
        pickerViewPresenter.selectButtonAction = { [weak self] () -> Void in
            guard let strongSelf = self else {
                return
            }
            let result = strongSelf.dataModel[pickerViewPresenter.currentlySelectedRow]
            pickerViewPresenter.hidePicker()
            // ...
        }

        return pickerViewPresenter
    }()

    private func presentPickerView {
        let index = 0 // [0..dataModel.count-1]
        pickerViewPresenter.selectRowAtIndex(index)
        pickerViewPresenter.showPicker()
    }

    // MARK: - UIPickerViewDataSource

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return dataModel.count
    }

    // MARK: - UIPickerViewDelegate

    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return "\(dataModel[row]) drunken sailors"
    }

}
Run Code Online (Sandbox Code Playgroud)

希望有人发现这个有用=)


bvo*_*ang 5

它可能不是您唯一的选择,但动画 UIPickerView 对您来说应该相对容易。添加选择器视图,使其显示在屏幕底部之外。什么时候动画它:

[UIView animateWithDuration:0.3 animations:^{
    self.datePicker.frame = CGRectMake(0, self.view.bounds.size.height - datePicker.bounds.size.height, datePicker.bounds.size.width, datePicker.bounds.size.height);
}];
Run Code Online (Sandbox Code Playgroud)

当需要隐藏它时:

[UIView animateWithDuration:0.3 animations:^{
    self.datePicker.frame = CGRectMake(0, self.view.bounds.size.height, datePicker.bounds.size.width, datePicker.bounds.size.height);
}];
Run Code Online (Sandbox Code Playgroud)


art*_*est 5

基于borisgolovnev 的建议CodeMonkey 的回答,我UITextFieldSwift 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]
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的 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()
}
Run Code Online (Sandbox Code Playgroud)

例子:

我已将其附加到UITapGestureRecognizer.

例子