当UITableViewCell被点击时,UILabel未按预期更新的行数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当UITableViewCell被点击时,UILabel未按预期更新的行数相关的知识,希望对你有一定的参考价值。

当点击单元格时,我正在更改自定义UITableViewCell标签上的numberOfLines属性。但是,直到第二次点击时才会在UI中反映出来。单元格在表格视图中配置为原型单元格,最初有2行。

有趣的是,当我在numberOfLines函数运行之前和之后打印出tapped()值时,值开始不同,然后同步 - 在第一次点击后,我看到函数运行前的2行,然后是函数运行后的0行。然而,在后续的点击之后,我在我的函数之前和之后看到了相同的值,这使得它似乎没有做任何事情,即使UI确实拉伸和缩小单元格,并且numberOfLines值在下次更改时会更改didSelectRowAtIndexPath功能运行。

我只是用tableView.reloadRows()看到这种行为。如果我使用tableView.reloadData()进行全面更新,则第一次点击时,单元格会适当地增长并折叠。然而,这感觉有点火腿,并没有像reloadRows()那样很好地制作动画。

TableView实现

    func tableView(_ tableView: UITableView, 
                       didSelectRowAt indexPath: IndexPath) {
         guard let cell = tableView.cellForRow(at: indexPath) as? ReviewTableViewCell
             else { return }
         let data = tableData[indexPath.row]

         print("old number of lines: (cell.detailLabel.numberOfLines)")

             //data.isOpen is set to false initially
             cell.tapped(data.isOpen)
         tableData[indexPath.row].isOpen = !data.isOpen
             tableView.reloadRows(at: [indexPath], with: .fade)

             print("old number of lines: (cell.detailLabel.numberOfLines)")


//      tableView.reloadData()
    }

自定义表视图单元格方法

    func tapped(_ isOpen: Bool) {
         if !isOpen {
              detailLabel.numberOfLines = 0     }
         else {
          detailLabel.numberOfLines = 2     }
    }

我希望这个代码在tableView.reloadRows()重新加载时扩展单元格,如果numberOfLines设置为0,当它设置为2时折叠单元格。这确实有效,但只有在单击两次+单元格之后。这也适用于第一次点击。

这是一个显示问题的gif链接:https://imgur.com/a/qe2uAXj

这是一个示例项目,类似于我的应用程序中发生的事情:https://github.com/imattice/CellLabelExample

答案

为了清楚起见,要获得这个技巧工作,UILabel一般必须限制在它的超视图的每一边,这样当它改变它的intrinsicContentSize能够推动每一方以容纳文本。 说,尝试使用这两种方法包装tapped方法:

tableView.beginUpdates()
if !isOpen {
    detailLabel.numberOfLines = 0     
}
else {
    detailLabel.numberOfLines = 2     
}
tableView.endUpdates()

当然tableview必须设置为自动大小:

tableView.estimatedRowHeight = <#What you want#>
tableView.rowHeight = UITableView.automaticDimension
另一答案

我能够弄清楚发生了什么。问题分为两部分。

第一部分是调用reloadRows()。此方法使用新单元格交换单元格,而不是更新已存在的单元格。因此,我正在更改隐藏交换单元格上的行数而不是视图中的单元格。 the docs中提到了这种行为:

重新加载行会导致表视图向其数据源询问该行的新单元格。该表动画化了新单元格,因为它为旧行设置了动画。

另外,我使用结构作为跟踪单元打开状态的数据模型。在Swift中,结构是写时复制,这意味着如果在该结构上更改了值,则会创建一个新结构,而不是更改我指向的结构的值。这意味着行tableData[indexPath.row].isOpen = !data.isOpen没有做任何有用的事情 - 我们查看索引路径中的tableData结构,获取它的isOpen值,复制一个新结构并更改新结构的isOpen值,然后将其抛出,因为新结构是未分配到任何地方

解决方案是不使用reloadRows()方法并使用A)class作为数据对象B)将indexPath.row中的数据替换为复制的struct

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) as? CustomCell else { return }
        var data = tableData[indexPath.row]

        tableView.beginUpdates()
        cell.tapped(isOpen: data.isOpen)
        data.isOpen = !data.isOpen

        tableData[indexPath.row] = data
        tableView.endUpdates()
    }

以上是关于当UITableViewCell被点击时,UILabel未按预期更新的行数的主要内容,如果未能解决你的问题,请参考以下文章

当单元格具有动态宽度时,CollectionView 中的间距不正确?

将 UITableViewCell 的子视图放在最前面

如何在 UITableViewCell 上保留子视图

当我点击 UITableViewCell 时,视图控制器没有被推送。

致命错误:在展开可选值时意外发现 nil - 当 UITextField 被点击时

如何判断在 UITableViewCell 中点击了一组图像