You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
}

额外优化点

  1. 移除oximeter_mode_UIPickerView.setValue(UIColor.black, forKey: "textColor"),该调用属于私有API操作,可能导致审核不通过或运行异常,改为直接在自定义Label上设置textColor。
  2. 确认rowHeightForComponent返回的80足够容纳多行文本,避免内容被截断。

内容的提问来源于stack exchange,提问作者Doug Null

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:35:18