仅在表格视图的特定单元格上显示和隐藏视图

时间:2018-03-31 10:52:54

标签: ios arrays swift uitableview uiview

我有自定义单元格的表格视图。它们非常高,因此屏幕上只能看到一个单元格,并且根据该单元格的位置,可能是第二个单元格的前25%。这些单元格表示具有名称的虚拟项目。每个单元格内部都有一个按钮。第一次点击时,它会在单元格内显示一个小UIView,并将该项目添加到数组中,并且第二次点击,隐藏它并删除该项目。添加和删​​除项目的部分工作正常,但是,由于在UITableView

中重复使用单元格,因此显示和隐藏视图存在问题

当我添加视图时,例如,在第一个单元格上,在第三个或第四个单元格上(在重复使用单元格之后),我仍然可以看到该视图。

为了防止这种情况,我试图循环项目数组并根据每个单元格的名称标签文本检查它们的名称。我知道这种方法效率不高(如果有成千上万的话怎么办?),但无论如何我都试过了。

以下是它的简单代码(checkedItems是项目数组,视图应该是可见的):

  if let cell = cell as? ItemTableViewCell {
        if cell.itemNameLabel.text != nil {

            for item in checkedItems {

                if cell.itemNameLabel.text == item.name {
                    cell.checkedView.isHidden = false

                } else {
                    cell.checkedView.isHidden = true

                }
            }
        }

这段代码乍看之下工作得很好,但在深入挖掘之后会出现一些问题。当我点击第一个单元格来显示视图,然后我点击第二个单元格以显示它上面的视图,它工作正常。但是,当我点击例如第一个和第三个时,第一个单元格上的视图消失,但该项仍然在数组中。我怀疑,原因仍然是细胞被重复使用的事实,因为细胞的高度相当大,所以第三个细胞在第三个细胞时是不可见的。我尝试在tableView(_:,cellForRow:)tableView(_:,willDisplay:,forRowAt:)方法中使用上面的代码,但结果是一样的。

所以,问题在于:我需要找到一种 EFFICIENT 方式来检查单元格,并在{{1}中的项目内显示 ONLY 视图数组。

EDITED 以下是单元格在没有视图的情况下的外观(紫色圆圈是按钮,视图是橙色圆圈)

The view is hidden

The view is visible

这是按钮的代码:

checkedItems

在细胞内:

protocol ItemTableViewCellDelegate: class {
func cellCheckButtonDidTapped(cell: ExampleTableViewCell)
 }

在视图控制器内部(注意:此处的代码只显示并隐藏视图。代码的目的是显示按钮如何与 @IBAction func checkButtonTapped(_ sender: UIButton) { delegate?.cellCheckButtonDidTapped(cell: self) } 交互):

table view

已编辑2

以下是extension ItemCellsTableViewController: ItemTableViewCellDelegate { func cellCheckButtonDidTapped(cell: ItemTableViewCell) { UIView.transition(with: cell.checkedView, duration: 0.1, options: .transitionCrossDissolve, animations: { cell.checkedView.isHidden = !cell.checkedView.isHidden }, completion: nil) } 方法的完整代码(我已从问题中删除了循环部分,以明确最初的方法是什么)。单元格上的tableView(_ cellForRowAt:)属性只设置项目的名称(item的{​​{1}})。

itemNameLabel

我已经尝试了解决方案,建议here,但这对我不起作用。

如果您遇到这样的问题并知道如何解决,我将非常感谢您的帮助和建议。

2 个答案:

答案 0 :(得分:1)

试试这个。

全球定义:var arrIndexPaths = NSMutableArray()

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:TableViewCell = self.tblVW.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell

    cell.textLabel?.text = String.init(format: "Row %d", indexPath.row)

    cell.btn.tag = indexPath.row
    cell.btn.addTarget(self, action: #selector(btnTapped), for: .touchUpInside)

    if arrIndexPaths.contains(indexPath) {
        cell.backgroundColor = UIColor.red.withAlphaComponent(0.2)
    }
    else {
        cell.backgroundColor = UIColor.white
    }

    return cell;
}


@IBAction func btnTapped(_ sender: UIButton) {
    let selectedIndexPath = NSIndexPath.init(row: sender.tag, section: 0)
    // IF YOU WANT TO SHOW SINGLE SELECTED VIEW AT A TIME THAN TRY THIS
    arrIndexPaths.removeAllObjects()
    arrIndexPaths.add(selectedIndexPath)
    self.tblVW.reloadData()
}

答案 1 :(得分:0)

我会将您单个细胞的状态保持为每个细胞后面的模式数据的一部分。

我假设您在tableView(_:,cellForRow:)中填充tableview时使用了一组模型对象。该模型是从一些后端服务填充的,该服务为您提供了一些JSON,然后在第一次加载视图时将其映射到模型对象。

如果向模型对象添加属性以指示是否已按下单元格,则可以在填充单元格时使用该属性。

你应该创建一个"包装器对象"包含原始JSON数据,然后包含一个包含状态的变量,我们称之为isHidden。您可以使用Bool值,也可以enum使用Bool。以下是仅使用struct MyWrappedModel { var yourJSONDataHere: YourModelType var isHidden = true init(yourJSONModel: YourModelType) { self.yourJSONDataHere = yourJSONModel } }

的示例
didSelectRow

在任何情况下,当你的单元格被点击时(在MyWrappedModel中),你会:

  1. 根据索引路径在包装的modeldata对象数组中找到正确的isHidden对象
  2. 切换
  3. 上的reloadRows(at:with:)
  4. 使用tableView(_:,cellForRow:)
  5. 在表格视图中重新加载受影响的行

    isHidden中,您现在可以检查是否...//fetch the modelObject for the current IndexPath cell.checkedView.isHidden = modelObject.isHidden 并根据该内容进行渲染:

    UITableViewCell

    此外,请知道方法prepareForReuse存在于checkedView上。当一个细胞即将被回收时,就会调用这种方法。这意味着您可以将其作为最后的手段来初始化"您的表格在呈现之前查看单元格。因此,在您的情况下,您可以隐藏struct Info : Decodable { let list : [List] } struct List : Decodable { let title : String let images : [URL] } 作为默认值。

    如果这样做,您不再需要使用数组来跟踪已敲击的单元格。 modeldata它自己知道它所处的状态,并且完全独立于细胞位置和回收。

    希望这有帮助。