Swift代码自定义PickerView遇到两个UI定制问题求助
PickerView 自定义问题解决方案
问题a:修改选中指示器(SelectionIndicator)颜色以隐藏
iOS新版本无法直接移除PickerView的选中指示器线条,可通过遍历PickerView子视图找到对应线条,将其颜色设置为与容器背景色一致实现隐藏。在viewDidLoad中添加以下代码:
// 遍历子视图定位选中指示器线条,修改颜色实现隐藏 for subview in pickerView.subviews { if subview.frame.height <= 1 { // 指示器线条高度通常小于等于1 subview.backgroundColor = viewContainer.backgroundColor } }
问题b:修复选中项背景圆角无效问题
当前代码存在两个问题:所有行都设置了背景,且创建Label时frame未确定导致圆角计算失效。需做以下修改:
- 区分选中与未选中行的样式,仅给选中行添加背景和圆角
- 手动指定Label的尺寸,确保圆角计算有效
- 开启
clipsToBounds保证圆角生效 - 选中行变化时刷新对应行的样式
修改后的代理方法及新增代码
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let pickerLabel: UILabel // 复用已存在的Label提升性能 if let reusedLabel = view as? UILabel { pickerLabel = reusedLabel } else { pickerLabel = UILabel() pickerLabel.font = UIFont(name: "Helvetica", size: 22) pickerLabel.textAlignment = .center // 手动设置Label尺寸,避免frame未确定的问题 pickerLabel.frame = CGRect(x: 0, y: 0, width: pickerView.bounds.width, height: 40) } pickerLabel.text = list[row] let isSelected = row == pickerView.selectedRow(inComponent: component) if isSelected { // 选中行样式 pickerLabel.textColor = #colorLiteral(red: 0.6829224825, green: 0.6091368198, blue: 0.9736139178, alpha: 1) pickerLabel.backgroundColor = #colorLiteral(red: 0.9468494058, green: 0.9369241595, blue: 1, alpha: 1) pickerLabel.layer.cornerRadius = 20 // 对应rowHeight=40,圆角设为高度的一半 pickerLabel.clipsToBounds = true // 必须开启才能显示圆角 } else { // 未选中行样式 pickerLabel.textColor = #colorLiteral(red: 0.6829224825, green: 0.6091368198, blue: 0.9736139178, alpha: 1) pickerLabel.backgroundColor = .clear pickerLabel.layer.cornerRadius = 0 } return pickerLabel } // 选中行变化时刷新样式 func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { let previousRow = pickerView.selectedRow(inComponent: component) pickerView.reloadRows(at: [IndexPath(row: previousRow, section: 0), IndexPath(row: row, section: 0)], with: .none) }
完整修改后的代码
import UIKit class ViewController: UIViewController { @IBOutlet weak var viewContainer: UIView! @IBOutlet weak var pickerView: UIPickerView! @IBOutlet weak var btnCancel: UIButton! @IBOutlet weak var btnConfirmation: UIButton! @IBOutlet weak var lb: UILabel! var list = ["Madrid", "Sidney", "Toronto", "NewYork", "Oslo"] override func viewDidLoad() { super.viewDidLoad() pickerView.dataSource = self pickerView.delegate = self viewContainer.layer.cornerRadius = 40 viewContainer.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) viewContainer.layer.shadowColor = #colorLiteral(red: 0.7647058824, green: 0.7647058824, blue: 0.7647058824, alpha: 1) viewContainer.layer.shadowOpacity = 0.7 viewContainer.layer.shadowRadius = 10 btnCancel.setTitle("Cancel", for: .normal) btnCancel.titleLabel?.font = UIFont(name: "Helvetica", size: CGFloat(16)) btnCancel.setTitleColor(.white, for: .normal) btnCancel.backgroundColor = #colorLiteral(red: 0.6829224825, green: 0.6091368198, blue: 0.9736139178, alpha: 1) btnCancel.layer.cornerRadius = btnCancel.frame.height/2.0 btnCancel.addTarget(self, action: #selector(tapBtnCancel(_ :)), for: .touchUpInside) btnConfirmation.setTitle("Confirm", for: .normal) btnConfirmation.titleLabel?.font = UIFont(name: "Helvetica", size: CGFloat(16)) btnConfirmation.setTitleColor(.white, for: .normal) btnConfirmation.backgroundColor = #colorLiteral(red: 0.6705882353, green: 0.6117647059, blue: 0.9490196078, alpha: 1) btnConfirmation.layer.cornerRadius = btnConfirmation.frame.height/2.0 btnConfirmation.addTarget(self, action: #selector(tapBtnConfirmation(_ :)), for: .touchUpInside) // 隐藏选中指示器线条 for subview in pickerView.subviews { if subview.frame.height <= 1 { subview.backgroundColor = viewContainer.backgroundColor } } } @objc func tapBtnCancel(_ sender: UIButton) { } @objc func tapBtnConfirmation(_ sender: UIButton) { lb.text = list[self.pickerView.selectedRow(inComponent: 0)] } } extension ViewController: UIPickerViewDataSource { func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return list.count } } extension ViewController: UIPickerViewDelegate { func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { return 40 } func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let pickerLabel: UILabel if let reusedLabel = view as? UILabel { pickerLabel = reusedLabel } else { pickerLabel = UILabel() pickerLabel.font = UIFont(name: "Helvetica", size: 22) pickerLabel.textAlignment = .center pickerLabel.frame = CGRect(x: 0, y: 0, width: pickerView.bounds.width, height: 40) } pickerLabel.text = list[row] let isSelected = row == pickerView.selectedRow(inComponent: component) if isSelected { pickerLabel.textColor = #colorLiteral(red: 0.6829224825, green: 0.6091368198, blue: 0.9736139178, alpha: 1) pickerLabel.backgroundColor = #colorLiteral(red: 0.9468494058, green: 0.9369241595, blue: 1, alpha: 1) pickerLabel.layer.cornerRadius = 20 pickerLabel.clipsToBounds = true } else { pickerLabel.textColor = #colorLiteral(red: 0.6829224825, green: 0.6091368198, blue: 0.9736139178, alpha: 1) pickerLabel.backgroundColor = .clear pickerLabel.layer.cornerRadius = 0 } return pickerLabel } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { let previousRow = pickerView.selectedRow(inComponent: component) pickerView.reloadRows(at: [IndexPath(row: previousRow, section: 0), IndexPath(row: row, section: 0)], with: .none) } }
内容的提问来源于stack exchange,提问作者iosSwift
相关产品推荐
相关产品推荐

