如何在UIPickerView中添加节标题?

时间:2016-12-29 22:12:15

标签: ios uipickerview

这绝不是必需品。如果可能的话会很好。我不确定是否可以这样做。

我有一个UIPickerView,它有41-42个选项。现在我按字母顺序排列所有选项。我希望他们被分成小组,在每个小组之前,我希望它有一个标题。类似于TableView的各个部分,你可以给每个部分一个标题。我想要选择器中每个部分的标题,但我不希望它是一个可选择的行。例如:

选择器选项:
核心(不可选择)
野蛮人(可选)
巴德(可选)
还有几个选择 APG(不可选)
炼金术士(可选)
骑士(可选)
还有几个选择 继续几个

这甚至可能吗?

3 个答案:

答案 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 {

}

screen

不是通过选择下一行强制选择,而是允许选择组,但不发送选择回调。但是为了确保触发没有设置任何可选项,您应该添加取消选择回调。

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
    }

}

现在您可以使用回调selecteddeselected将您的用户界面更改为启用或禁用按钮。

有关完整示例,请参阅我刚刚发布的示例代码: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。

UIPickerView example

答案 2 :(得分:-1)

不,我不认为标准选择器视图提供该选项。也就是说,您可以将UIPickerView子类化,并教您的自定义子类,以便在您描述时使用节分隔符。

尽管工作量很大,但创建你自己的控件肯定是可能的,这个控件就像你描述的部分那样就像一个选择器。