【问题标题】:filterTableViewController.reloadRows reloading rows only on first callfilterTableViewController.reloadRows 仅在第一次调用时重新加载行
【发布时间】:2017-09-26 22:26:53
【问题描述】:

我有一个表,每行有 3 行,每行带有检查按钮。我正在做的是当我选择所有三个按钮时,我想单击取消按钮,该按钮在视图中,而不是同一控制器上的表,以重新加载所有 3 行调用转到自定义单元格类,其中 uncheck 设置为 true 并重新加载行。对于第一次尝试它工作正常,我可以看到要重新加载的正确索引。第二次当我选择所有 3 个检查按钮并再次单击取消时,我可以看到要重新加载的正确索引,但调用不会再次自定义单元类,复选框仍然处于选中状态。知道为什么吗? 我总是在我的数组中获得正确的索引。

取消按钮代码-:

@IBAction func cancelDataItemSelected(_ sender: UIButton) {
    for index in selectedButtonIndex{
            let indexPath = IndexPath(item: index, section: 0)
            print(selectedButtonIndex)
            filterTableViewController.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
    }
    selectedButtonIndex .removeAll()
    print(selectedButtonIndex)
}

表格代码-:

extension filterControllerViewController:UITableViewDataSource,UITableViewDelegate
{
    // NUMBER OF ROWS IN SECTION
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
      return ControllerData.count
     }

    // CELL FOR ROW IN INDEX PATH
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
     let Cell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! ControllerCellTableViewCell
    Cell.filterTableMenu.text = ControllerData[indexPath.item]
     Cell.radioButtonTapAction = {
     (cell,checked) in
     if let radioButtonTappedIndex =  tableView.indexPath(for: cell)?.row{
        if checked == true {
          self.selectedButtonIndex.append(radioButtonTappedIndex)
    }
        else{
            while self.selectedButtonIndex.contains(radioButtonTappedIndex) {
                if let itemToRemoveIndex = self.selectedButtonIndex.index(of: radioButtonTappedIndex) {
                    self.selectedButtonIndex.remove(at: itemToRemoveIndex)
                 }
              }
           }
        }
    }
     return filterCell
}

自定义类-:

var radioButtonTapAction : ((UITableViewCell,Bool)->Void)?
     //MARK-:awakeFromNib()
        override func awakeFromNib() {
            super.awakeFromNib()
            filterTableSelectionStyle()
            self.isChecked = false
        }

        // CHECKED RADIO BUTTON IMAGE
        let checkedImage = (UIImage(named: "CheckButton")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal))! as UIImage
        // UNCHECKED RADIO BUTTON IMAGE
        let uncheckedImage = (UIImage(named: "CheckButton__Deselect")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal))! as UIImage
        // Bool STORED property
        var isChecked: Bool = false {
            didSet{
                // IF TRUE SET TO CHECKED IMAGE ELSE UNCHECKED IMAGE
                if isChecked == true {
                  TableRadioButton.setImage(checkedImage, for: UIControlState.normal)
                } else {
                  TableRadioButton.setImage(uncheckedImage, for: UIControlState.normal)
                }
            }
        }
        // FILTER CONTROLLER RADIO BUTTON ACTION

        @IBAction func RadioButtonTapped(_ sender: Any) {
            isChecked = !isChecked
            radioButtonTapAction?(self,isChecked)
        }

【问题讨论】:

  • 是否正在重新加载行?也就是说,您是否接到电话到cellForRowAt?如果有,那代码是什么?
  • @DonMag 是的,当我使用 UITableViewRowAnimation.top 时会重新加载行
  • @DonMag 已更新

标签: ios swift3 tableview tableviewcell


【解决方案1】:

请记住,单元格被重复使用,并且 reloadRows 只是告诉行重绘。当用户选中单元格中的复选框时,新的选中状态应保存在底层数据源中,并将该状态标记在 cellForRowAtIndexPath 中的单元格中。否则,单元格复选框会显示用户最后一次为所有索引设置的状态,而不是基础数据源的状态。

【讨论】:

  • 你能给我看一个你在说什么的例子吗?或者告诉我我错在哪里,以便我可以处理它。作为单元的一部分被重复使用,我只有 3 个单元。该部分滚动前第一次可见的单元格不是可重复使用的单元格。只有在滚动出可见屏幕时才会重复使用单元格。
  • 看看你的 cellForRowAt 委托函数。你在里面画复选框吗?我看到您正在radioButtonTapAction 中为TableRadioButton 设置图像。我没有看到新状态与基础数据一起保存。因此,将选中状态保存在底层数据中,重新加载表(或仅行)的数据,并根据数据状态在 cellForRowAt 中调用 TableRadioButton.setImage。
  • 直接更改单元格时,要么在重新加载数据时更改,要么在重复使用单元格时传播到其他索引。从数据源重新加载后,始终在 cellForRowAt 中绘制单元格。
  • 我将检查状态保存在单选按钮上单击它从 false 变为 true,因此我的 isChecked 是具有属性观察者的存储属性 didSet 它执行属性更改并为真实条件工作。然后我传递在我的控制器类中的关闭帮助下,真正的状态和单元格并保存点击的索引。现在,当我再次点击相同的按钮时,属性为 true,它变为 false,在我的其他情况下,我从数组中删除了保存索引。跨度>
【解决方案2】:

对“可重用”表格单元格如何工作的根本误解。

假设您的表格视图足够高,以至于只有 8 个单元格可见。显然需要创建 8 个单元格,并且在滚动时会重复使用它们。

可能显而易见的是,单元格在重新加载时会被重用。换句话说,每次调用.reloadData 时——即使您只是重新加载一个当前可见的单元格——该单元格也会被重用。它没有重新创建。

因此,关键要点是:任何初始化任务在第一次创建单元格时发生。之后,单元格会被重复使用,如果您想要“状态”条件(例如选中或未选中按钮),您可以将单元格“重置”到其原始状态。

正如所写,您的cellForRowAt 函数仅设置.filterTableMenu.text ...它忽略.isChecked 状态。

您几乎可以通过设置单元格的.isChecked 值来解决问题,但是您还以比需要更复杂的方式跟踪开/关状态。不要使用数组来追加/删除行索引,而是使用布尔数组,并且只需使用 array[row] 来获取/设置值。

那么您的cellForRowAt 函数将如下所示:

// CELL FOR ROW IN INDEX PATH
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let filterCell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! ControllerCellTableViewCell

    // set the label in filterCell
    filterCell.filterTableMenu.text = ControllerData[indexPath.item]

    // set current state of checkbox, using Bool value from out "Tracking Array"
    filterCell.isChecked = self.selectedButtonIndex[indexPath.row]

    // set a "Callback Closure" in filterCell
    filterCell.radioButtonTapAction = {
        (checked) in
        // set the slot in our "Tracking Array" to the new state of the checkbox button in filterCell
        self.selectedButtonIndex[indexPath.row] = checked
    }

    return filterCell

}

您可以在此处查看一个工作示例:https://github.com/DonMag/CheckBoxCells

【讨论】:

  • 很棒的解释人非常感谢您清除了这个问题并展示了一些新的想法+100票。
猜你喜欢
  • 2019-11-28
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多