您不需要子类化 UIPickerView 来实现这一点,而是需要仔细实现数据源和委托。
我建议你有一个实现这两者的类,作为一个测试,我这样做了:
import UIKit
class PickerViewSource: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
init(pickerView: UIPickerView) {
super.init()
pickerView.dataSource = self
pickerView.delegate = self
}
var selected: (([String: Any]) -> Void)?
let data = [
["title": "Group a", "selectable": false],
["title": "title a1", "selectable": true],
["title": "title a2", "selectable": true],
["title": "title a3", "selectable": true],
["title": "Group b", "selectable": false],
["title": "title b1", "selectable": true],
["title": "title b2", "selectable": true],
["title": "Group c", "selectable": false],
["title": "title c1", "selectable": true],
["title": "title c2", "selectable": true],
]
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return data.count
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let d = data[row]
if let selectable = d["selectable"] as? Bool, selectable == true {
if let view = view as? ItemView, let title = d["title"] as? String{
view.label.text = title
return view
}
let view = ItemView()
if let title = d["title"] as? String{
view.label.text = title
}
return view
}
if let selectable = d["selectable"] as? Bool, selectable == false {
if let view = view as? GroupView, let title = d["title"] as? String{
view.label.text = title
return view
}
let view = GroupView()
if let title = d["title"] as? String{
view.label.text = title
}
return view
}
return UIView()
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
var index = row
if let selectable = data[row]["selectable"] as? Bool, selectable == false {
index += 1
pickerView.selectRow(index, inComponent: 0, animated: true)
}
selected?(data[index])
}
}
如你所见,这个类有一个回调var selected: (([String: Any]) -> Void)?。只有可选项目才会调用它。
ViewController 实例化源并设置回调:
class ViewController: UIViewController {
var pickerViewSource: PickerViewSource?
@IBOutlet weak var pickerView: UIPickerView! {
didSet{
pickerViewSource = PickerViewSource(pickerView: pickerView)
pickerViewSource?.selected = {
selected in
print(selected)
}
}
}
}
为了完整起见,观点:
class BaseView: UIView {
var label: UILabel = UILabel()
override func layoutSubviews() {
super.layoutSubviews()
self.addSubview(label)
label.frame = self.bounds
}
}
class GroupView: BaseView {
override func layoutSubviews() {
super.layoutSubviews()
label.backgroundColor = .orange
}
}
class ItemView: BaseView {
}
您可以允许选择组,但不要发送选择回调,而不是通过选择下一行来强制选择。但是为了确保触发没有设置任何可选择的内容,您应该添加一个取消选择回调。
var selectedElement: [String:Any]?
var deselected: (([String: Any]) -> Void)?
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if let element = selectedElement {
deselected?(element)
selectedElement = nil
}
if let selectable = data[row]["selectable"] as? Bool, selectable == true {
let element = data[row]
selected?(element)
selectedElement = element
}
}
现在您可以使用回调 selected 和 deselected 来更改您的用户界面,即启用或禁用按钮。
完整示例请参见我刚刚发布的示例代码:https://github.com/vikingosegundo/PickerWithSectionTitlesExample