这绝不是必需品。如果可能的话会很好。我不确定是否可以这样做。
我有一个UIPickerView
,它有41-42个选项。现在我按字母顺序排列所有选项。我希望他们被分成小组,在每个小组之前,我希望它有一个标题。类似于TableView的各个部分,你可以给每个部分一个标题。我想要选择器中每个部分的标题,但我不希望它是一个可选择的行。例如:
选择器选项:
核心(不可选择)
野蛮人(可选)
巴德(可选)
还有几个选择
APG(不可选)
炼金术士(可选)
骑士(可选)
还有几个选择
继续几个
这甚至可能吗?
答案 0 :(得分:1)
您不需要继承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)
}
}
}
}
和completness,视图:
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
答案 1 :(得分:0)
编辑:正如@Duncan C在他的回答中提到的那样。在iOS7 +中没有内置的解决方案。我的回答提供了另一种实现目标的方法。
在iOS 7之前,您可以使用
showsSelectionIndicator
在选择器视图中的不同对象上不显示选定状态。但iOS7 +不允许这样做:在iOS 7及更高版本中,您无法自定义选择器视图的选择指示器。始终显示选择指示器,因此将此属性设置为false无效。
相反,你可以做一些讨厌的黑客攻击:
委托采用UIPickerViewDelegate协议,并为每个组件的行提供内容,作为属性字符串,普通字符串或视图,它通常响应新的选择或取消选择。
这个简短的例子只是展示了一个解决方案如何运作。要使这些不可选的选择器对象,您可以使用文档中提到的与其余文件不同的属性字符串。
如果用户尝试选择其中一个标题对象,则无法关闭选择器视图。用户必须选择另一个选项,并且随着时间的推移,用户将了解到这些带有粗体字符串的对象是不可选的。
var datasource = ["Core", "content", "content", "content", "APG", "content", "content"]
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
print(self.datasource[row])
switch row {
case 0:
// create attributed string
let myString = datasource[row]
let myAttribute: [String:Any] = [ NSForegroundColorAttributeName: UIColor.blue, NSUnderlineStyleAttributeName: NSUnderlineStyle.styleDouble.rawValue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
return myAttrString
case 15:
let myString = datasource[row]
let myAttribute: [String:Any] = [
NSForegroundColorAttributeName: UIColor.blue,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleDouble.rawValue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
return myAttrString
case 4:
let myString = datasource[row]
let myAttribute: [String:Any] = [
NSForegroundColorAttributeName: UIColor.blue,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleDouble.rawValue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
return myAttrString
default:
//It all depends on your datasource, but if you have 0-42 strings(core, APG included) you can just output the rest under default here
let myString = datasource[row]
let myAttribute: [String:Any] = [ NSForegroundColorAttributeName: UIColor.black]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
return myAttrString
}
}
它看起来不太好,但是你可以自定义你想要的方式。您还可以在选取器视图对象中添加图像或UiView。
答案 2 :(得分:-1)
不,我不认为标准选择器视图提供该选项。也就是说,您可以将UIPickerView子类化,并教您的自定义子类,以便在您描述时使用节分隔符。
尽管工作量很大,但创建你自己的控件肯定是可能的,这个控件就像你描述的部分那样就像一个选择器。