Swift中替换titleForRow为viewForRow后UIPickerView不显示行
UIPickerView 切换到 viewForRow 后无法显示内容的解决办法
问题背景
使用titleForRow时UIPickerView显示正常,为实现多行文本显示替换为viewForRow方法后,该方法会正常触发(打印的文本内容正确),但PickerView中看不到任何行内容。
问题代码
class CentralViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat { return 80.0 } func open_mode_UIPickerView() { oximeter_mode_UIPickerView = UIPickerView() oximeter_mode_UIPickerView.delegate = self oximeter_mode_UIPickerView.dataSource = self oximeter_mode_UIPickerView.backgroundColor = UIColor.white oximeter_mode_UIPickerView.setValue(UIColor.black, forKey: "textColor") oximeter_mode_UIPickerView.autoresizingMask = .flexibleWidth oximeter_mode_UIPickerView.contentMode = .center mode_UIPickerView_x = 0 mode_UIPickerView_y = 10 mode_UIPickerView_width = Int(UIScreen.main.bounds.size.width / 3) mode_UIPickerView_height = 300 oximeter_mode_UIPickerView.frame = CGRect( x: mode_UIPickerView_x, y: mode_UIPickerView_y, width: mode_UIPickerView_width, height: mode_UIPickerView_height ) self.view.addSubview(oximeter_mode_UIPickerView) view.bringSubviewToFront(oximeter_mode_UIPickerView) } func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let label: UILabel if let view = view { label = view as! UILabel } else { label = UILabel(frame: CGRect( x: mode_UIPickerView_x, y: mode_UIPickerView_y, width: mode_UIPickerView_width, height: mode_UIPickerView_height )) } label.text = "" label.lineBreakMode = .byWordWrapping label.numberOfLines = 0 if row == 0 { label.text = "Oxi mode 0" + "\n Red Red" + "\n 620 660" print("titleForRow label.text", label.text ) } if row == 1 { label.text = "Oxi mode 1" + "\n Orange Red" + "\n 590 730" print("titleForRow label.text", label.text ) } if row == 2 { label.text = "Oxi mode 2" + "\n Violet IR" + "\n 420 830" print("titleForRow label.text", label.text ) } if row == 3 { label.text = "Oxi mode 3" + "\n Green IR" + "\n 520 940" print("titleForRow label.text", label.text ) } label.sizeToFit() return label }
断点调试信息
return (<UILabel: 0x104e20dd0; frame = (0 10; 87.3333 61); text = 'Oxi mode 0\nRed Red\n6...'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x281d830c0>> )
问题原因及修复方案
核心问题
创建Label时错误使用了PickerView在父视图中的坐标(mode_UIPickerView_x、mode_UIPickerView_y)作为Label自身的frame偏移量,导致Label被放置到了PickerView的可视区域之外,所以看不到内容。PickerView的行内子视图应该以自身局部坐标系(x=0,y=0)来设置位置。
修复后的viewForRow方法
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { let label: UILabel // 安全复用已有Label,避免强制类型转换崩溃 if let existingLabel = view as? UILabel { label = existingLabel } else { // 以PickerView组件的宽度作为Label宽度,x、y设为0(局部坐标系) let componentWidth = pickerView.rowSize(forComponent: component).width label = UILabel(frame: CGRect(x: 0, y: 0, width: componentWidth, height: 80)) label.lineBreakMode = .byWordWrapping label.numberOfLines = 0 label.textAlignment = .center // 确保文本居中显示 label.textColor = .black // 直接设置文本颜色,替代私有API调用 } // 用switch替代多个if,代码更简洁 switch row { case 0: label.text = "Oxi mode 0\nRed Red\n620 660" case 1: label.text = "Oxi mode 1\nOrange Red\n590 730" case 2: label.text = "Oxi mode 2\nViolet IR\n420 830" case 3: label.text = "Oxi mode 3\nGreen IR\n520 940" default: label.text = "" } label.sizeToFit() // 确保Label在组件内水平居中 label.center.x = pickerView.rowSize(forComponent: component).width / 2 return label }
额外优化点
- 移除
oximeter_mode_UIPickerView.setValue(UIColor.black, forKey: "textColor"),该调用属于私有API操作,可能导致审核不通过或运行异常,改为直接在自定义Label上设置textColor。 - 确认
rowHeightForComponent返回的80足够容纳多行文本,避免内容被截断。
内容的提问来源于stack exchange,提问作者Doug Null
相关产品推荐
相关产品推荐

