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

Table View数据展示:单选题式单选选项布局实现咨询

嘿,针对你想用两个Label实现「问题展示+单选选项行布局」的需求,我给你梳理下可行的方案~首先得提一句:别用Label放可选择的选项,因为Label是纯展示控件,没有交互能力和内置的选中状态管理机制,强行加手势会徒增复杂度,换用下面这些组件会更省心:

方案一:UIStackView + UIButton(轻量首选,适合选项少的场景)

如果你的选项数量不多、一行能放下,用水平布局的UIStackView搭配UIButton是最简单的方案,还能轻松实现单选逻辑:

步骤说明

  1. 把原来计划放答案的Label替换成UIStackView,设置为水平布局,调整spacing(选项间距)和alignment(垂直对齐方式)
  2. 给每个选项创建UIButton,自定义选中/未选中的样式(比如背景色、文字颜色区分)
  3. 所有按钮绑定同一个点击事件,在事件方法里实现单选逻辑:点击某个按钮时,先取消之前选中按钮的状态,再标记当前按钮为选中

示例代码

class ViewController: UIViewController {
    @IBOutlet weak var questionLabel: UILabel!
    @IBOutlet weak var optionStackView: UIStackView!
    
    // 模拟选项数据
    private let options = ["选项A", "选项B", "选项C", "选项D"]
    // 记录当前选中的按钮
    private var selectedOptionButton: UIButton?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupOptionButtons()
    }
    
    private func setupOptionButtons() {
        // 先清空StackView原有内容
        optionStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
        
        for option in options {
            let button = UIButton(type: .system)
            button.setTitle(option, for: .normal)
            // 自定义样式
            button.setTitleColor(.darkText, for: .normal)
            button.setTitleColor(.white, for: .selected)
            button.backgroundColor = .systemGray5
            button.layer.cornerRadius = 8
            button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
            // 绑定点击事件
            button.addTarget(self, action: #selector(optionButtonTapped(_:)), for: .touchUpInside)
            optionStackView.addArrangedSubview(button)
        }
    }
    
    @objc private func optionButtonTapped(_ sender: UIButton) {
        // 单选逻辑:取消之前选中的按钮,选中当前按钮
        selectedOptionButton?.isSelected = false
        sender.isSelected = true
        selectedOptionButton = sender
        
        // 获取选中的选项内容(这里可以根据需求做后续处理)
        if let selectedOption = sender.title(for: .selected) {
            print("当前选中:\(selectedOption)")
        }
    }
}

方案二:UICollectionView(适合选项多、需要横向滚动的场景)

如果选项数量较多、一行放不下需要横向滚动,用UICollectionView会更灵活,还能复用单元格:

步骤说明

  1. 把答案区域替换成UICollectionView,设置横向滚动属性,用UICollectionViewFlowLayout指定水平滚动方向
  2. 自定义UICollectionViewCell,内部放置一个UIButton来承载选项,通过cell的isSelected属性管理选中状态
  3. 在ViewController里实现数据源和代理方法,处理单选逻辑:选中新cell时,刷新旧选中cell的状态,标记当前cell为选中

示例代码

// 自定义选项单元格
class OptionCollectionViewCell: UICollectionViewCell {
    static let reuseID = "OptionCell"
    
    let optionButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitleColor(.darkText, for: .normal)
        btn.setTitleColor(.white, for: .selected)
        btn.backgroundColor = .systemGray5
        btn.layer.cornerRadius = 8
        btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
        btn.translatesAutoresizingMaskIntoConstraints = false
        return btn
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupSubviews()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupSubviews()
    }
    
    private func setupSubviews() {
        contentView.addSubview(optionButton)
        NSLayoutConstraint.activate([
            optionButton.topAnchor.constraint(equalTo: contentView.topAnchor),
            optionButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            optionButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            optionButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    }
    
    // 通过cell的isSelected属性同步按钮状态
    override var isSelected: Bool {
        didSet {
            optionButton.isSelected = isSelected
            optionButton.backgroundColor = isSelected ? .systemBlue : .systemGray5
        }
    }
}

// ViewController部分
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    @IBOutlet weak var questionLabel: UILabel!
    @IBOutlet weak var optionCollectionView: UICollectionView!
    
    private let options = ["选项A", "选项B", "选项C", "选项D", "选项E", "选项F"]
    // 记录当前选中的选项索引
    private var selectedOptionIndex: Int?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
    }
    
    private func setupCollectionView() {
        optionCollectionView.register(OptionCollectionViewCell.self, forCellWithReuseIdentifier: OptionCollectionViewCell.reuseID)
        // 设置横向滚动布局
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumInteritemSpacing = 12
        layout.sectionInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
        optionCollectionView.collectionViewLayout = layout
        optionCollectionView.isScrollEnabled = true
    }
    
    // MARK: UICollectionView数据源
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return options.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OptionCollectionViewCell.reuseID, for: indexPath) as! OptionCollectionViewCell
        cell.optionButton.setTitle(options[indexPath.item], for: .normal)
        // 设置初始选中状态
        cell.isSelected = indexPath.item == selectedOptionIndex
        return cell
    }
    
    // MARK: UICollectionView代理(处理选中事件)
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        // 取消之前选中的cell状态
        if let oldIndex = selectedOptionIndex {
            let oldCell = collectionView.cellForItem(at: IndexPath(item: oldIndex, section: 0)) as! OptionCollectionViewCell
            oldCell.isSelected = false
        }
        // 标记当前cell为选中
        selectedOptionIndex = indexPath.item
        let currentCell = collectionView.cellForItem(at: indexPath) as! OptionCollectionViewCell
        currentCell.isSelected = true
        
        // 获取选中的选项内容
        print("当前选中:\(options[indexPath.item])")
    }
}

额外注意点

  • 样式可以根据你的需求调整,比如按钮的圆角大小、颜色搭配、内边距等,让选项更贴合产品设计
  • 单选状态的管理要统一,要么用变量记录选中的按钮/索引,要么通过控件的isSelected属性维护,避免状态混乱

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:03:31