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

水平UIPickerView单元格尺寸设置及内容适配问题求助

解决水平UIPickerView在50x50尺寸下的单元格文本适配问题

你遇到的核心问题是UIPickerView旋转后坐标系的映射关系没理清,加上自定义单元格的文本没有做自适应处理,导致50x50尺寸下长文本显示异常。下面是具体的修复方案:

关键调整点

  • 修正PickerView的frame与旋转逻辑:旋转-90度后,PickerView的宽高会互换,需要重新设置原始frame并调整位置,确保最终显示为50x50的水平样式。
  • 适配单元格的尺寸与文本显示:给自定义label开启自动缩小字体或换行功能,让长文本能在有限空间内完整展示;同时修正rowHeightForComponent和widthForComponent的返回值,匹配旋转后的实际显示尺寸。
  • 移除硬编码布局:用AutoLayout替代固定frame,避免布局冲突,提升视图复用性。

修复后的完整代码

import UIKit
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    var data = ["Hello", "WorldWorld", "Of", "PickerPickerPicker", "View"]
    let viewPicker = UIPickerView()
    let pickerTargetSize: CGFloat = 50 // 目标显示的宽高
    let labelFont = UIFont(name:"verdana", size: 24.0)!

    override func viewDidLoad() {
        super.viewDidLoad()
        viewPicker.delegate = self
        viewPicker.dataSource = self
        viewPicker.layer.borderColor = UIColor.black.cgColor
        viewPicker.layer.borderWidth = 1.5
        
        // 旋转PickerView为水平方向
        let rotationAngle = -90 * (.pi / 180)
        viewPicker.transform = CGAffineTransform(rotationAngle: rotationAngle)
        
        // 旋转后宽高互换,所以原始frame宽设为目标尺寸,高设为父视图宽度(容纳所有选项)
        viewPicker.frame = CGRect(x: 0, y: 0, width: pickerTargetSize, height: view.frame.width)
        // 调整center,让PickerView在屏幕中央水平展示
        viewPicker.center = CGPoint(x: view.center.x, y: view.center.y + (view.frame.width - pickerTargetSize)/2)
        self.view.addSubview(viewPicker)
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return data.count
    }

    // 旋转后,rowHeight对应PickerView的显示宽度(即我们要的50)
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return pickerTargetSize
    }

    // 旋转后,widthForComponent对应每个选项的高度,可动态计算最长文本高度确保显示完整
    func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
        let maxTextHeight = data.map { $0.heightOfString(usingFont: labelFont) }.max() ?? pickerTargetSize
        return max(maxTextHeight, pickerTargetSize)
    }

    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let cellView = view as? UIView ?? UIView()
        cellView.backgroundColor = .clear
        
        // 复用label,避免重复创建
        let label: UILabel
        if let existingLabel = cellView.viewWithTag(100) as? UILabel {
            label = existingLabel
        } else {
            label = UILabel()
            label.tag = 100
            label.textAlignment = .center
            label.font = labelFont
            // 开启自动缩小字体,适配长文本
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.5
            // 可选:允许换行,需打开下面注释
            // label.numberOfLines = 0
            cellView.addSubview(label)
            
            // 用AutoLayout约束label,替代硬编码frame
            label.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                label.centerXAnchor.constraint(equalTo: cellView.centerXAnchor),
                label.centerYAnchor.constraint(equalTo: cellView.centerYAnchor),
                label.widthAnchor.constraint(equalTo: cellView.widthAnchor, multiplier: 0.9),
                label.heightAnchor.constraint(equalTo: cellView.heightAnchor, multiplier: 0.9)
            ])
        }
        
        label.text = data[row]
        // 旋转label抵消PickerView的旋转,让文本正向显示
        label.transform = CGAffineTransform(rotationAngle: 90 * (.pi / 180))
        return cellView
    }
}

extension String {
    func widthOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.width
    }
    
    func heightOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.height
    }
}

核心逻辑说明

  1. PickerView布局:旋转后将原始frame的宽设为50,高设为父视图宽度,确保横向有足够空间容纳所有选项,再通过center调整到屏幕中央。
  2. 文本适配:开启adjustsFontSizeToFitWidth让长文本自动缩小字体,也可以选择开启换行(设置numberOfLines=0),两种方式都能解决文本截断问题。
  3. 视图复用:复用已有的cell和label,提升性能;用AutoLayout替代硬编码frame,避免旋转后出现布局错位。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:45