在 UIPickerView 中更改选定行的颜色,滚动时也是如此
Posted
技术标签:
【中文标题】在 UIPickerView 中更改选定行的颜色,滚动时也是如此【英文标题】:Change color of selectedRow in UIPickerView, also when rolling 【发布时间】:2017-11-01 05:10:58 【问题描述】:我必须更改UIPickerView
中所选行的颜色。
我确实设法改变了颜色,我知道这个问题已经有好几个回复了,无论如何这些都不能让我满意:通过这些实现,pickerview 的动画有问题,我不喜欢它。
这是当前解决方案的代码
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
var label: UILabel
if view == nil
label = UILabel()
else if view is UILabel
label = view as! UILabel
else
label = UILabel()
let title: NSAttributedString
if self.model?.selectedValue == row
title = UIPickerView.attributedString(with: .selectedRow, text: "\(model?.years[row] ?? 0)")
else
title = UIPickerView.attributedString(with: .unselectedRow, text: "\(model?.years[row] ?? 0)")
label.attributedText = title
return label
当用户滚动时,我会重新加载组件。
但正如您在下图中看到的,当用户滚动时,绿色区域会移动,并且有几分之一秒的时间,绿色标签位于选择器指示器下方,而选定的行为黑色。
我想要的是选择器指示器内部的所有内容都是绿色的,而外部保持默认的灰色阴影。
我该如何实现?
【问题讨论】:
【参考方案1】:您应该为此使用attributedTitleForRow
,而无需使用NSAttributedString
创建您自己的标签。在您的didSelectRow
中,您重新加载所有组件,以便能够重置所有颜色并将新选择的颜色设置为绿色。
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString?
let color = (row == pickerView.selectedRow(inComponent: component)) ? UIColor.green : UIColor.black
return NSAttributedString(string: self.model[row], attributes: [NSForegroundColorAttributeName: color])
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
pickerView.reloadAllComponents()
【讨论】:
已经试过了,但是不行。我仍然可以看到年份变黑然后变绿。 不明白你的意思。滚动时要删除绿色吗? 不,我想要这样,当您向上或向下滚动时,选择视图中有一半字符串,另一个(未选择)中有一半字符串,它变成一半绿色和一半灰色。在默认实现中,没有颜色,当您滚动时,您可以看到标签半纯黑色和半黑色,alpha AttributeTitleForRow 有效。 self.model 引用您的数组,其中数据加载到选择器中。 为什么不只是pickerView.reloadComponent(component)?【参考方案2】:你可以简单地使用这个代码
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
let label = view as? UILabel ?? UILabel()
if pickerView.selectedRow(inComponent: component) == row
label.backgroundColor = UIColor.green
label.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
label.layer.cornerRadius = 18
label.layer.masksToBounds = true
label.textColor = .white
label.text = String(numbers[row])
label.textAlignment = .center
else
label.layer.cornerRadius = 25
label.frame = CGRect(x: 0, y: 0, width: 36, height: 36)
label.layer.cornerRadius = 18
label.layer.masksToBounds = true
label.textColor = .white
label.text = String(numbers[row])
label.textAlignment = .center
return label
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
pickerView.reloadAllComponents()
【讨论】:
你找到方法了吗?所选行一直持续到用户移开手指【参考方案3】:效果更好,性能稍差。
extension ViewController: UIPickerViewDelegate
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
let info = BeatScalar.generalRates[row]
let general = GeneralRateItem(info.cn, info.ita, info.val)
// gray every row
general.unselected()
decorateView(pickerView, row: row)
return general
// Here is the logic
func decorateView(_ picker: UIPickerView, row: Int)
var frame = picker.frame
frame.origin.y = frame.origin.y + frame.size.height * 0.42
frame.size.height = frame.size.height * 0.16
let mini = max(row-1, 0)
// 19 is total number
let maxi = min(18, row+1)
for i in mini...maxi
if i != row, let item = picker.view(forRow: i, forComponent: 0) as? GeneralRateItem
let f = item.convert(item.frame, to: picker)
if frame.intersects(f) == false
// highlight the center row
item.selected()
func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat
return 44
extension ViewController: UIPickerViewDataSource
func numberOfComponents(in pickerView: UIPickerView) -> Int
return 1
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int // 19 is total number
return 19
【讨论】:
以上是关于在 UIPickerView 中更改选定行的颜色,滚动时也是如此的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中为选定的 UIPickerView 行设置动画背景颜色