【问题标题】:UITableViewCell layout not updating until cell is reusedUITableViewCell 布局在重用单元格之前不会更新
【发布时间】:2016-11-10 18:05:54
【问题描述】:

我有一个 UITableView,我用自动调整单元格填充。 UITableView 设置相当简单:

    tableView.estimatedRowHeight = 70
    tableView.rowHeight = UITableViewAutomaticDimension

就像苹果在这里推荐的那样:https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html

要启用自调整大小的表格视图单元格,您必须设置表格视图的 UITableViewAutomaticDimension 的 rowHeight 属性。你还必须 为estimatedRowHeight 属性赋值。只要两者 设置好这些属性后,系统使用 Auto Layout 来计算 行的实际高度。

在配置单元格时,我还会禁用/启用一些约束以实现所需的外观。这就是事情变得有趣的地方。在重新使用单元格之前,不会更新单元格布局。字面上地。您可以调用layoutIfNeeded()、setNeedsLayout()、layoutSubviews() 或任何其他方法,您无法强制单元格更新其布局。

所有其他方面都工作得很好:标签确实改变了它们的文本,你隐藏/取消隐藏视图,但布局被卡住,直到单元格被重用。

问题:是什么原因造成的以及如何避免这种行为?

【问题讨论】:

    标签: ios swift uitableview autolayout


    【解决方案1】:

    不幸的是,提供的答案/cmets 都没有为我解决。我总是以最初不正确的布局结束。只有在重用单元格或调用reloadData()(在表格视图上)后,它才能正确显示。

    以下是唯一对我有用的东西。我不是这种 hack 的忠实粉丝,但是在这个看似非常简单的布局问题上花了大约半天时间后,我就放弃了。 >.

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    

    或者,您也可以在viewDidAppear 中调用reloadData(没有DispatchQueue hack),但是当布局从“不正确”跳转到“正确”时,您可以清楚地看到“跳转”。

    无论如何,只是想分享我的经验,希望这对其他人有所帮助。干杯!

    【讨论】:

    • viewWillAppear 总是在主线程上调用。
    • 这不是关于线程,而是关于异步“延迟”。
    • 在搜索了 SO、Apple 论坛和互联网上的随机位置之后,这是唯一真正为我解决的问题。
    【解决方案2】:

    我也遇到了你的问题。而不是删除

    tableView.estimatedRowHeight = 70
    

    我刚刚在 cellForRow 方法的末尾添加了一个 layoutIfNeeded,就在返回单元格本身之前:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as? MyCustomCell
        ...
        cell?.layoutIfNeeded()
        return cell!
    }
    

    结果:单元格布局总是完美的,第一次和每次重复使用。

    【讨论】:

      【解决方案3】:

      就我而言,问题是由estimatedRowHeight 引起的。

      只需删除此行

      tableView.estimatedRowHeight = 70
      

      解决了我的问题。 Cell 正确更新了它的布局,它几乎解决了我的问题。

      但是,您很可能会遇到另一个麻烦,因为您的单元格的高度设置为 43.5 磅。您的日志也将充满自动布局错误,其中将包括这样的一行

      <NSLayoutConstraint:0x600000097570 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fd4ee511d20.height == 43.5   (active)>
      

      显然,如果您不提供estimatedRowHeight,表格视图会对单元格的内容视图设置 43.5 磅的高度限制,并且如果您的单元格的“内部”高度不匹配(概率为 99.99%),然后它会将错误放入日志中。

      如何避免该错误?我还不知道。 我发布了一个关于这个问题的问题,一旦我找到答案,我会在这个问题中提供一个链接。

      【讨论】:

        【解决方案4】:

        在重用单元格之前不会更新单元格布局

        如果您希望 tableview 反映更改的单元格布局。

        改变单元格布局后重绘表格视图

                tableView.beginUpdates()
                tableView.setNeedsDisplay()
                tableView.endUpdates()
        

        例如:

            func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                guard let cell = tableView.cellForRow(at: indexPath) as? CustomCell else { return }
                cell.collapseDescriptionLabel()
                
                // redraw the tableView
                tableView.beginUpdates()
                tableView.setNeedsDisplay()
                tableView.endUpdates()
            }
        

        【讨论】:

          【解决方案5】:

          您不需要使用layoutIfNeeded()、setNeedsLayout() 和layoutSubviews() 来强制布局。您可以使用tableView.beginUpdates() 和tableView.endUpdates()。

          例如:

          func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                  let cell = tableView.cellForRow(at: indexPath)
                  tableView.beginUpdates()
                  cell.heightConstraint.constant = 50
                  tableView.endUpdates()
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-26
            • 1970-01-01
            相关资源
            最近更新 更多