防止在第一次单击后检查最后一个单元格行,反之亦然&将选定的行添加/删除到数组

Posted

技术标签:

【中文标题】防止在第一次单击后检查最后一个单元格行,反之亦然&将选定的行添加/删除到数组【英文标题】:Preventing last cell row being checked after clicking first and vice versa & adding/removing selected rows to array 【发布时间】:2018-03-14 12:13:45 【问题描述】:

我使用 tableview 来显示字符串数组。当我单击特定行时,我希望它用复选标记突出显示。当我取消选择一行时,我希望删除复选标记。当我按下一个按钮时,我希望当前突出显示的行在一个数组(newFruitList)中传递出去。

我的问题是,当我单击第一行时,最后一行被突出显示。当我取消选中第一行时,最后一行未选中,好像它们是同一个单元格?

我该如何克服这个问题?

另外,我在新数组中添加和删除的方式,这是正确的方法吗? 谢谢

我的代码:

class BookingViewController: UIViewController, ARSKViewDelegate, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource 


    @IBOutlet weak var table: UITableView!

    let fruits = ["Apples", "Oranges", "Grapes", "Watermelon", "Peaches"]
    var newFruitList:[String] = []

    override func viewDidLoad() 
        super.viewDidLoad()
        self.table.dataSource = self
        self.table.delegate = self
        self.table.allowsMultipleSelection = true



    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return fruits.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        var cell = table.dequeueReusableCell(withIdentifier: "Cell")
        if cell == nil
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
        

        cell?.textLabel?.text = fruits[indexPath.row]
        return cell!
    

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        newFruitList.append(fruits[indexPath.row])
        if let cell = tableView.cellForRow(at: indexPath) 
            cell.accessoryType = .checkmark

        

    

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) 
        if let index = newFruitList.index(of: fruits[indexPath.row]) 
            newFruitList.remove(at: index)
        
        if let cell = tableView.cellForRow(at: indexPath) 
            cell.accessoryType = .none
        

    

    @IBAction func bookButtonPressed(_ sender: UIButton) 

//testing purposes
        for i in stride(from: 0, to: newFruitList.count, by: 1)
           print(newFruitList[i])
        

    

【问题讨论】:

【参考方案1】:

它们可能是同一个单元格,因为您使用 dequeueReusableCell 并且它重用了旧单元格。

使用:

override func prepareForReuse() 
        super.prepareForReuse()
    

重置单元格应该没问题。

至于保存和发送任务。创建一个可以填充的预索引数组。

var selected: [Bool] = []
var fruits: [Fruit] = [] 
     didSet 
        selected = Array(repeating: false, count: fruits.count)
     

在你的 didSelectItemAt 你做:

selected[indexPath.item] = !selected[indexPath.item]

【讨论】:

所以在我的 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 方法中,我会在声明单元格变量后执行 cell.prepareForReuse 吗? 啊,对了,你没有使用自定义单元格?然后直接在初始化单元集的时候cell.accessoryType = .none【参考方案2】:

UITableView 重复使用已经存在的单元格,因此您会看到重复的复选标记,因此要解决此问题,您需要在加载单元格时清除单元格状态。为此,您可以创建一个具有属性的模型来跟踪所选单元格的状态

所以你的水果模型必须如下所示

class Fruit
    var name:String
    var isSelected:Bool
    init(name:String)
        isSelected = false
        self.name = name
    

然后您将使用Fruit 列表填充表格视图

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        var cell = table.dequeueReusableCell(withIdentifier: "Cell")
        if cell == nil
            cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell")
        
       let model = fruits[indexPath.row]
       cell?.textLabel?.text = model.name
       if(model.isSelected)
           cell.accessoryType = .checkmark
       
       else
          cell.accessoryType = .none
       

        return cell!



 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        newFruitList.append(fruits[indexPath.row])

        if let cell = tableView.cellForRow(at: indexPath) 
            cell.accessoryType = .checkmark
            var model = fruits[indexPath.row]
            model.isSelected = true
        

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) 
        if let index = newFruitList.index(of: fruits[indexPath.row]) 
            newFruitList.remove(at: index)
        
        if let cell = tableView.cellForRow(at: indexPath) 
            cell.accessoryType = .none
            var model = fruits[indexPath.row]
            model.isSelected = false
        

    

【讨论】:

模型应该被创建为结构,并且不应该包含var,而是let structs 是值类型,所以在这种情况下,它不会在更改状态时更新列表中的模型,也让是常量并且不会更改值,因此使用 var 行 if let model = 导致错误?条件绑定的初始化程序必须具有 Optional 类型,而不是 'BookingViewController.Contact' 这是为了安全地展开选项,所以如果你的模型不是可选的,你可以跳过展开部分并在那里使用普通的 let 或 var 语句 无法使用类型为“(of: Fruit)”的参数列表调用“index”??

以上是关于防止在第一次单击后检查最后一个单元格行,反之亦然&将选定的行添加/删除到数组的主要内容,如果未能解决你的问题,请参考以下文章

一次加载 10 个单元格行 - 快速

在选定的单元格行返回 TableView

故事板中的自定义单元格行高度设置没有响应

防止在外部单击时以弹出模式关闭单元格编辑器

Xcode Swift 4 调用 self.tableView.reload() 以减少单元格行数

如何单击具有单击事件的元素下的按钮