出队的 UITableViewCell 在滚动之前布局不正确(使用自动布局)

Posted

技术标签:

【中文标题】出队的 UITableViewCell 在滚动之前布局不正确(使用自动布局)【英文标题】:dequeued UITableViewCell has incorrect layout until scroll (using autolayout) 【发布时间】:2013-02-21 06:01:01 【问题描述】:

我有一个自定义 UITableViewCell 子类,它在 Interface Builder 中应用了自动布局约束。该单元格包含多个视图,包括UITextField

相应地,UITextField 的大小受到限制,使其与下一个视图之间存在默认水平间距。

单元格实例化如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    static NSString *CellIdentifier = @"ProgressCell";
    ProgressCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                                     forIndexPath:indexPath]

    cell.textField.text = @"Some string that is different for each cell";

    return cell;

当单元格第一次出现时,UITextField 超出了正确的框架,并出现在其右侧的UIView 后面。但是,当我将单元格滚动出屏幕、暂停然后向后滚动时,文本会被正确截断。

下面显示了一个示例(在第二次编辑时)。

我尝试为cellForRowAtIndexPath 中的单元格调用[cell setNeedsLayout][cell setNeedsDisplay],并在延迟后执行它们。两者都无效。

什么是滚动屏幕导致单元格正确显示,我该如何复制此问题或解决根本问题?

编辑:

打电话

[self.tableView reloadData];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];

为了重新加载单元格,似乎会导致布局第一次正确显示。

但是,它现在在滚动时中断(偶尔)(即,当向上滚动时,布局约束现在没有正确应用)。

cellForRowAtIndexPath 中调用[cell setNeedsLayout] 似乎无法解决此问题。

编辑2:

顶部单元格,如here 所示,正确显示(与底部单元格一样),直到我向下滚动屏幕。它从此消失了。

这反映了第一次编辑时的问题 - 这是第二次渲染的问题(让我认为这可能与重用单元格有关?)

【问题讨论】:

您是否收到任何有关控制台约束的警告? 你能附上一些截图吗? @rdelmar 我写了我的自动布局类别(我们之前没有讨论过吗?)如果您有兴趣:commandshift.co.uk/blog/2013/02/20/… 我在这里上传了一个示例图片:imgur.com/a/IKv0Z。控制台@rdelmar 中没有约束警告——它们都是通过 IB 设置的,所以它们应该是有效的。 我看不出这些限制有什么问题。我试图复制你的问题,但我的截断了长文本而不滚动。如果您使宽度约束 = 而不是 >= 有帮助吗?你可以删除那个(这将取决于你对右边的其他 2 个对象有什么)? 【参考方案1】:

如果您将属性命名为 UITableViewCell 子类 textLabeldefaultTextLabel,那么 IB 将忽略您指定的约束并用默认约束覆盖它们,不会发出警告。

即使在 IB 中使用自定义样式设计的单元格也是如此,这些单元格没有可见的 textLabeldetailTextLabel 属性。

如果在 UITableViewCell 子类上添加 UIImageView 类型的属性并将其命名为 imageView,也会发生这种情况。

【讨论】:

“imageView”属性也是如此。 这个答案需要提升到 UITableViewCell 类参考,我只是浪费了4个小时的生命。凌晨 4 点... 非常感谢。你救了我几个小时的命。 我希望 Interface Builder 或编译器给你一个关于无意覆盖这些属性名称的警告。 对于名为“maskView”的 UIImageView 属性也是如此。【参考方案2】:

按照这个multiple lines UILabel GitHub issue,这是一个挥之不去的ios bug。

我发现在iOS 9+中,这种情况多发生在编辑模式,具有很大的不可预测性。

以下解决方法仅部分有效:它需要重绘UITableView 两次,但仍不能涵盖所有场景。

override func viewDidLoad() 
    super.viewDidLoad()

    tableView.setNeedsLayout()
    tableView.layoutIfNeeded()
    tableView.reloadData()


注意事项:

使用UITextView 是多行UILabel 的绝佳替代方案,没有错误。 UITextView 也没有表现出任何 IULabel 的其他古怪之处,例如 alignment errors 或 flickering。 SO-25947146 上还有一个替代解决方案,它对我不起作用,但值得一提。 当self.tableView.editingtrue 时似乎很突出 对tableView.estimatedRowHeight 使用较低的值会减少发生率 SwiftArchitect/TableViewControllerRowHeightBug gist 上的错误演示

【讨论】:

【参考方案3】:

在我的例子中,我在 viewDidAppear 中调用了方法 tableView.reloadData() 并且布局显示正确

override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)
    self.tableView.reloadData()

【讨论】:

这种方法已经在 5 年前的上一个答案中提出。 @miken32 因为我试图在 viewDidLoad 上写它并且没有工作所以......

以上是关于出队的 UITableViewCell 在滚动之前布局不正确(使用自动布局)的主要内容,如果未能解决你的问题,请参考以下文章

动态/可出队的 UITableviewcells 内的 UITextfield

UITableViewCell AFNetworking 仅加载一次带有动画的图像

出队后,CALayer 在自定义 UITableViewCell NIB 上消失

使用出队的 dequeueReusableCell - 出队后单元格的 textField

如何防止出队的集合视图单元格相互重叠?

原子出队的最简单方法?