setNeedsLayout仅在显示之后重新布局单元格

时间:2014-01-04 18:53:48

标签: ios uitableview autolayout

我有一个带有单元格的表格视图,有时会有一个可选的UI元素,有时候必须删除它。 根据元素,调整标签大小。

当细胞初始化时,它比以后更窄。当我将数据设置到标签中时,将从cellForRowAtIndexPath:

调用此代码
if (someFlag) {
    // This causes layout to be invalidated
    [flagIcon removeFromSuperview];
    [cell setNeedsLayout];
}

之后,单元格返回到表视图,并显示它。但是,该点的文本标签已调整其宽度,但不调整高度。大约在一秒左右后调整高度,并且当已经显示所有单元格时,清晰可见。

重要提示,这只是在初始创建前几个单元格时。一旦它们被重复使用,一切都很好,因为删除了可选视图,并且标签的大小已经正确地用于以前的用法。

为什么在setNeedsLayout之后但是在显示之前,细胞没有完全重新铺设? UIKit不应该在显示之前检查无效布局吗?

如果我这样做

if (someFlag) {
    [flagIcon removeFromSuperview];
    [cell layoutIfNeeded];
}

所有内容都会立即调整,但这似乎是一种不正确的编写代码的方法,我觉得我错过了其他的东西。


关于如何创建单元格的更多代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ProfileCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    [cell setData:model.items[indexPath.row] forMyself:YES];
    return cell;
}

// And in ProfileCell:
- (void)setData:(Entity *)data forMyself:(BOOL)forMe
{
    self.entity = data;

    [self.problematicLabel setText:data.attributedBody];
    // Set data in other subviews as well

    if (forMe) {
        // This causes layouts to be invalidated, and problematicLabel should resize
        [self.reportButton removeFromSuperview];
        [self layoutIfNeeded];
    }
}

此外,如果重要,在storyboard单元格中如下所示,可选约束接管一旦标记图标被删除: Constraints in the storyboard

2 个答案:

答案 0 :(得分:3)

我同意调用layoutIfNeeded似乎是错误的,即使它适用于您的情况。但我怀疑你错过了什么。虽然我没有对这种方式进行过任何研究,但根据我在表单元格中使用自动布局的经验进行动态布局有点儿麻烦。也就是说,在运行时删除或向细胞添加子视图时,我看到了笨拙的生涩布局。

如果您正在寻找替代策略(使用自动布局),您可以继承UITableViewCell并覆盖layoutSubviews。自定义表格单元格可以在其公共API中公开一个标志,该标志可以在tableView:cellForRowAtIndexPath:的实现中设置。单元格的layoutSubviews方法将使用该标志来确定它是否应包含可选的UI元素。我不保证这会消除这个问题。

第二种策略是设计两种不同的细胞类型,并在tableView:cellForRowAtIndexPath:中根据需要在两者之间进行交换。

答案 1 :(得分:0)

您已在问题中添加了其他代码,因此我有另一个建议。在单元格的setData:forMyself:方法中,尝试调用setNeedsUpdateConstraints而不是layoutIfNeeded