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
相关产品推荐
相关产品推荐

