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

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未确定导致圆角计算失效。需做以下修改:

  1. 区分选中与未选中行的样式,仅给选中行添加背景和圆角
  2. 手动指定Label的尺寸,确保圆角计算有效
  3. 开启clipsToBounds保证圆角生效
  4. 选中行变化时刷新对应行的样式

修改后的代理方法及新增代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 21:50:40