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

UITableView与Slider交互异常:首次选中行滑块值不更新

问题描述

我正在做UITableView与Slider的交互实验,需求是:选中表格中的一行,滑块显示该行对应标签的数值;滑块值变化时,更新选中行的标签。除了应用启动后的首次选中操作外,其余功能都正常。

启动应用后选中第一行(对应数值为65),didSelectRowAt方法正确返回65,并且将slider.value设置为该值,但紧接着的打印语句显示slider.value为1.0,应用中的滑块也显示1.0。

再次点击第一行时,方法仍能正确识别数值65,且滑块值被正确设置为65;选择其他行时应用功能也正常。请问哪里出错了,导致首次选中时滑块值不更新?

代码如下:

import UIKit

class ViewController: UIViewController { 
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var slider: UISlider!{
        didSet{
            slider.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi/2))
        }
    }
    
    @IBAction func sliderValueChanged(_ sender: Any) {
        if selectedRowIndexPath == [] {return}//no row selected
        
        let cell = tableView.cellForRow(at: selectedRowIndexPath)
        let pField = cell?.contentView.viewWithTag(1) as? UILabel
        pField?.text = String(format: "%d", Int(slider.value))
        blendSolution[selectedRowIndexPath.row].p = Double(slider.value)
        Swift.print(slider.value)
    }
    
    struct Gas {
        var fO2, fHe, fN2, p, pCum, c, lO2, lHe, lN2 : Double
        var desc = String()
        init(fO2: Double, fHe: Double, p: Double, pCum: Double, c:Double){
            self.fO2 = fO2
            self.fHe = fHe
            self.fN2 = 1 - fO2 - fHe
            self.p = p
            self.pCum = pCum
            self.c = c
            self.lO2 = fO2 * p * c
            self.lHe = fHe * p * c
            self.lN2 = (1 - fO2 - fHe) * p * c
            self.desc = gasDesc(fO2: fO2, fHe: fHe)
        }
        func gasDesc(fO2: Double, fHe: Double) -> String {
            if fO2 == 0.21 {return "Air"}
            if fO2 == 1.0 {return "O2"}
            if fHe == 1.0 {return "He"}
            if fHe == 0 {return "EAN\(Int(round(fO2 * 100)))"}
            return "\(Int(round(fO2 * 100)))/\(Int(round(fHe * 100)))"
        }
    }
    
    var selectedRowIndexPath = IndexPath()
    
    let startGas = Gas(fO2: 0.12, fHe: 0.50, p:45, pCum: 45, c: 3)
    let targetGas = Gas(fO2: 0.16, fHe: 0.36, p:232, pCum: 232, c: 3)
    var deltaGas = (lO2: Double(), lHe: Double(), lN2: Double())
    var blendSolution = [Gas]()
    var c = Double()

    override func viewDidLoad() {
            super.viewDidLoad()
        
        tableView.dataSource = self
        tableView.delegate = self
        tableView.isEditing = true
        
        blendSolution = [
            Gas(fO2: 0.17, fHe: 0.45, p:65.0, pCum: 65.0, c: 3),
            Gas(fO2: 0.09, fHe: 0.65, p:40.0, pCum: 105.0, c: 3),
            Gas(fO2: 0.12, fHe: 0.66, p:20.0, pCum: 125.0, c: 3),
            Gas(fO2: 0.21, fHe: 0, p:30.0, pCum: 155.0, c: 3),
            Gas(fO2: 0.0, fHe: 1.0, p:40.0, pCum: 195.0, c: 3),
            Gas(fO2: 1.0, fHe: 0.0, p:15.0, pCum: 210.0, c: 3),
            Gas(fO2: 0.32, fHe: 0.0, p:22.0, pCum: 232.0, c: 3)
        ]
        
        c = targetGas.c
    }
}

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return blendSolution.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "blendSolutionCell", for: indexPath)
        let pField = cell.contentView.viewWithTag(1) as! UILabel
        pField.text = String(Int(round(blendSolution[indexPath.row].p)))
        
        let gasField = cell.contentView.viewWithTag(2) as! UILabel
        gasField.text = String(blendSolution[indexPath.row].desc)
        
        let pCum = cell.contentView.viewWithTag(3) as! UILabel
        pCum.text = String(Int(round(blendSolution[indexPath.row].pCum)))
        
        let intGas = cell.contentView.viewWithTag(4) as! UILabel
        intGas.text = "Dummy"
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        Swift.print("value \( Float(blendSolution[indexPath.row].p))")
        slider.value = Float(blendSolution[indexPath.row].p)
        Swift.print("slider \(slider.value)")
        slider.maximumValue = 232
        slider.minimumValue = 0
        selectedRowIndexPath = indexPath
    }
    
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        let movedObject = self.blendSolution[sourceIndexPath.row]
        blendSolution.remove(at: sourceIndexPath.row)
        blendSolution.insert(movedObject, at: destinationIndexPath.row)
    }
    
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        //disallow delete
        return .none
    }
    
    func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
        //remove indent when editing
        return false
    }
}
解决方案

问题出在滑块的最小值和最大值设置时机上。

首次选中行时,你先设置了slider.value = 65,之后才设置slider.minimumValue = 0和slider.maximumValue = 232。而UISlider默认的最小值是0,最大值是1.0,当你把value设为65时,这个值超过了默认的最大值1.0,滑块会自动把值 clamp(限制)到最大值1.0,所以打印出来是1.0。后续点击时,滑块已经有了正确的最大值232,所以设置65就能正常生效。

修复方法:

方法一:调整代码顺序

在didSelectRowAt里先设置滑块的范围,再设置value:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    Swift.print("value \( Float(blendSolution[indexPath.row].p))")
    // 先设置范围
    slider.minimumValue = 0
    slider.maximumValue = 232
    // 再设置值
    slider.value = Float(blendSolution[indexPath.row].p)
    Swift.print("slider \(slider.value)")
    selectedRowIndexPath = indexPath
}

方法二:提前设置滑块范围

把滑块的min和max设置移到viewDidLoad里,不用每次选中行都重复设置,代码更简洁:

override func viewDidLoad() {
    super.viewDidLoad()
    
    tableView.dataSource = self
    tableView.delegate = self
    tableView.isEditing = true
    
    // 提前设置滑块范围
    slider.minimumValue = 0
    slider.maximumValue = 232
    
    blendSolution = [
        // ... 你的数组内容
    ]
    
    c = targetGas.c
}

此时didSelectRowAt只需设置value即可:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    Swift.print("value \( Float(blendSolution[indexPath.row].p))")
    slider.value = Float(blendSolution[indexPath.row].p)
    Swift.print("slider \(slider.value)")
    selectedRowIndexPath = indexPath
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:34:54