如何在 UIPickerView 中添加部分标题?
Posted
技术标签:
【中文标题】如何在 UIPickerView 中添加部分标题?【英文标题】:How do I add section titles in a UIPickerView? 【发布时间】:2016-12-29 22:12:14 【问题描述】:这绝不是需要的东西。如果可能的话会很好。我不确定这是否可以做到。
我有一个UIPickerView
,它将有 41-42 个选项。现在,我按字母顺序排列了所有选项。我希望他们被分成几组,在每组之前我希望它有一个标题。类似于 TableView 具有部分的方式,您可以为每个部分指定一个标题。我想要选择器中每个部分的标题,但我不希望它成为可选行。例如:
选择器选项: 核心(不可选择) 野蛮人(可选) 吟游诗人(可选) 更多选项 APG(不可选择) 炼金术士(可选) 骑士(可选) 更多选项 继续几个
这甚至可能吗?
【问题讨论】:
你可以这样做 您能详细说明一下吗?除了 Duncan C 建议的方法之外,还有其他方法吗?有教程链接吗? 等一下..制作一些快速示例代码 【参考方案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)
为了完整起见,观点:
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
【讨论】:
【参考方案2】:编辑:正如@Duncan C 在他的回答中提到的那样。在 ios7+ 中没有内置的解决方案。我的回答提供了另一种实现目标的方法。
在 iOS 7 之前,您可以使用
showsSelectionIndicator
在选取器视图中不显示不同对象的选定状态。但是 iOS7+ 不允许这样做:在 iOS 7 及更高版本上,您无法自定义选取器视图的选择指示器。选择指示器始终显示,因此将此属性设置为 false 无效。
相反,您可以做一些讨厌的 hack:
委托采用 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。
【讨论】:
为了改善这一点,如果用户选择了带有章节标题的行,则自动将选择更新到下一行。【参考方案3】:不,我认为标准选择器视图不提供该选项。也就是说,您也许可以继承 UIPickerView 并教您的自定义子类具有您所描述的部分分隔符。
当然可以,尽管需要做更多的工作,但可以创建自己的控件,该控件的作用类似于您描述的部分的选择器。
【讨论】:
谢谢你。现在我不想把事情复杂化。试图让我的应用程序简单。我正在学习 Xcode 和 swift。我现在可以把它放在次要位置,直到我更好地理解这门语言。与其说是必需品,不如说是奢侈品。UIPickerViewDelegate
的pickerView(_:viewForRow:forComponent:reusing:)
可能会被强制为组指示符和可选项目返回不同的视图。不需要子类化。
好的,我会进一步研究。我将阅读 Apple 的文档,并寻找教程。我不确定从哪里开始寻找。这是一个很好的起点。谢谢你。
@DuncanC,请看我的回答。以上是关于如何在 UIPickerView 中添加部分标题?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 UIActionSheet 中添加 UIPickerView
如何在 UIAlertController 中添加 UIPickerView?