【问题标题】:UISwitch state in Tableviewcell resets when user scrolls - Swift当用户滚动时,Tableviewcell 中的 UISwitch 状态会重置 - Swift
【发布时间】:2018-11-12 08:42:30
【问题描述】:

我已经搜索了有关此问题的解决方案,但似乎都不适用于我的用例。

我在视图控制器中有一个表,我面临的问题是,当滚动 UISwitch 状态时,它被重置为 OFF。我知道表格单元格被重用了,但是我如何实现一个解决方案,当用户根据我下面的代码滚动时恢复 UISwitch 的状态

import UIKit

class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{

@IBOutlet weak var mylabel: UILabel!
var myString = String()

@IBAction func stirrBtn(_ sender: AnyObject) {
}

var timeSelected = String()
var selectedTimeArr = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    mylabel.text = myString
    self.timeSelected = myString
}

func switchChanged(_ sender : UISwitch!){
    print("table row switch Changed \(sender.tag)")
    print("The switch is \(sender.isOn ? "ON" : "OFF")")
    let kValue = (sender.tag + 1)
    let keyValue = String(kValue)
    if sender.isOn {
        recipeSettings.boolStirrSwitch[keyValue] = true
        recipeSettings.switchedOnArr.append(keyValue)

    } else {
        recipeSettings.boolStirrSwitch[keyValue] = false
    }
}

public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    let stringNum = Int(self.timeSelected)
    recipeSettings.recipeTimeSet2 = stringNum!
    return(stringNum)!
}


public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
    //here is programatically switch make to the table view
    let switchView = UISwitch(frame: .zero)
    switchView.setOn(false, animated: true)
    switchView.tag = indexPath.row // for detect which row switch Changed
    switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
    cell.accessoryView = switchView

    // Process data displayed in rows(minutes)
    let endTime = Int(self.timeSelected)
    let startTime = Int(1)

    // Recipe time array
    let timeArray: [Int]  = Array(startTime...endTime!)
    let stringTimeArr = timeArray.map{String($0)}

    // Save time array to global variable
    recipeSettings.recipeTimeSetArr = stringTimeArr

    // Create a boolean Array to hold all default false booleans
    let defBool: Bool = false
    var defBoolArr: [Bool] = []

    // Fill the array with the defaults boolean
    for _ in 0..<stringTimeArr.count{defBoolArr.append(defBool)}

    // Map the array to global dictionary containing the Time in an array and default "false" value

    for i in 0..<stringTimeArr.count {
        recipeSettings.boolStirrSwitch[stringTimeArr[i]] = defBoolArr[i]
    }

    // Add the minutes to cell table
    cell.textLabel?.text = stringTimeArr[indexPath.row]
    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
}

正如您在我的代码中看到的,我确实将每个 UI 开关的状态保存在一个全局变量字典中。如何解决 UISwitch 基于此代码更改状态的问题?感谢所有帮助。提前致谢

【问题讨论】:

  • 试试这个设置你保存在 recipeSettings.boolStirrSwitch 中的 SwitchView 状态和它的标签值
  • if let switchState = recipeSettings.boolStirrSwitch[indexPath.row + 1]{ if switchState{ switchView.isOn = true }else{ switchView.isOn = false } }else{ switchView.isOn = false }
  • @GovindKumawat 感谢您的回复。我已经在cellForRowAt 中尝试过该代码。我收到“对成员下标的模糊引用”错误。
  • 你能显示你在哪里定义 recipeSettings.boolStirrSwitch 吗?
  • // 使用默认布尔值填充数组。在您的cellForRowAt 中,您的开关状态将一遍又一遍地更改为let defBool: Bool = false false,因此请使用另一种方法,然后重新加载表。

标签: uitableview swift3 uiswitch


【解决方案1】:
var switchState = [String : Bool]()
  • 您的recipeSettings.boolStirrSwitch 应该像这样被清除。
  • 当您使用 timeSelected 作为 numberOfRowsInSection 时,如图所示 你的 cell.textLabel ,所以你不需要额外的stringTimeArr 为此。
  • 您在cellForRowAt 中所做的所有处理都会再次发生并且 再次重复使用表格单元格,以便在另一个中设置数据 function 然后reload TableView

您的问题的解决方案应该是这样的。

import UIKit

class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{

//make tableView IBOutlet for reloading data
@IBOutlet weak var tableView: UITableView!

@IBOutlet weak var mylabel: UILabel!
var myString = String()

@IBAction func stirrBtn(_ sender: AnyObject) {
}

var timeSelected = String()
var selectedTimeArr = [String]()

override func viewDidLoad() {
    super.viewDidLoad()
    mylabel.text = myString
    self.timeSelected = myString
    self.setdefaultSwitchState()
}

//recipeSettings.boolStirrSwitch should be decleard like that
var switchState = [String : Bool]()

//setDeaultSwitchState
func setdefaultSwitchState(){
    if let timeSelected = Int(self.timeSelected){
        for value in 0..<timeSelected{
            switchState["\(value)"] = false
            //or
            //recipeSettings.boolStirrSwitch["\(value)"] = false
        }
    }
    self.tableView.reloadData()
}


@objc func switchChanged(_ sender : UISwitch!){
    print("table row switch Changed \(sender.tag)")
    print("The switch is \(sender.isOn ? "ON" : "OFF")")
    let kValue = (sender.tag + 1)
    let keyValue = String(kValue)
    if sender.isOn {
        switchState[keyValue] = true

    } else {
        switchState[keyValue] = false
    }
}

public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    let stringNum = Int(self.timeSelected)
    recipeSettings.recipeTimeSet2 = stringNum!
    return(stringNum)!
}


public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
    //here is programatically switch make to the table view
    let switchView = UISwitch(frame: .zero)
    switchView.setOn(false, animated: true)
    switchView.tag = indexPath.row // for detect which row switch Changed
    switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
    cell.accessoryView = switchView


    cell.textLabel?.text = "\(indexPath.row + 1)"
    if let switchState = switchState["\(indexPath.row)"] {
        if switchState{
            switchView.isOn = true
        }else{
            switchView.isOn = false
        }
    }else{
        switchView.isOn = false
    }

    return cell
}


func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
}

【讨论】:

  • 再次感谢您提供更详细的答案。我快到了。我不得不将self.tableView.reloadData() 更改为self.tableView?.reloadData(),因为我收到EXC_BAD_INSTRUCTION(code=EXC_i386_INVOP, subcode=0x0) 错误。但是现在它出现了奇怪的行为,当用户滚动时,除了第一个单元格之外,每个单元格的状态都被重新加载。即使最初选择为 ON,它也总是将其重置为 OFF
  • 显示你的StirrViewController更新你的问题让我看看你已经走了多远。
  • func switchChanged(_ sender : UISwitch!) 中,当开关状态改变let kValue = (sender.tag + 1) 时,它总是会错过第一个单元格的状态,总是将其更改为let kValue = (sender.tag)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-07
  • 2014-10-28
相关资源
最近更新 更多