16

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

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

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

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

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

4

6 回答 6

31

附加一个 UIPickerView 作为您已添加到视图中的 0 尺寸 UITextField 的 inputView。

let picker = UIPickerView()
picker.dataSource = self
picker.delegate = self
        
let dummy = UITextField(frame: .zero)
view.addSubview(dummy)
        
dummy.inputView = picker
dummy.becomeFirstResponder()
于 2016-04-27T20:38:44.677 回答
10

更好的选择仍然是使用UITextField. 您不必在屏幕上实际显示它。只需将其放入 0x0UIView使其不可见,将其设置inputView为您的UIPickerView并调用becomeFirstResponder它以显示选择器并resignFirstResponder隐藏它。

UIView拥有一个实现所有这些以及方法的子类UIPickerViewDelegate很方便UIPickerViewDataSource

于 2015-07-12T13:35:15.563 回答
8

至少对我和 Swift4 + Autolayout 解决方案来说,最干净的方法UITextField是添加 aUIView作为顶部视图/按钮的容器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
}()

我习惯SnapKit以编程方式布局我的视图。您可以使用timePicker'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()
    }

嵌入顶视图

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)
}

结果如下所示:

在此处输入图像描述

于 2018-03-13T11:20:19.987 回答
7

我接受了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?()
    }

}

然后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"
    }

}

希望有人觉得这很有用=)

于 2016-03-24T20:27:22.330 回答
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);
}];

当需要隐藏它时:

[UIView animateWithDuration:0.3 animations:^{
    self.datePicker.frame = CGRectMake(0, self.view.bounds.size.height, datePicker.bounds.size.width, datePicker.bounds.size.height);
}];
于 2013-03-18T18:53:10.890 回答
5

根据borisgolovnev 的建议CodeMonkey 的回答,我在Swift 5UITextField中以以下方式实现了一个不可见的想法。

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]
    }
}

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()
}

例子:

我已将其附加到UITapGestureRecognizer.

例子

于 2020-04-27T09:36:25.263 回答