所有这些自动布局更新方法有什么区别?都有必要吗?

Dou*_*ith 28 objective-c uiview ios autolayout nslayoutconstraint

在下面的代码中,调用这四种方法进行布局推理.我有点困惑为什么所有这些都是需要的,以及它们彼此不同的做法.它们在过程中用于通过自动布局使单元格的高度变为动态.(来自该库这个问题.)

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)

它来自这个单元格高度的代码块:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

    RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [cell updateFonts];

    NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
    cell.titleLabel.text =  [dataSourceItem valueForKey:@"title"];
    cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];

    cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f);

    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
    [cell.contentView setNeedsLayout];
    [cell.contentView layoutIfNeeded];

    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    return height;
}
Run Code Online (Sandbox Code Playgroud)

但他们的做法有何不同?他们为什么都需要?

ily*_* n. 45

布局

假设您将视图逻辑封装在UIView子类中,并调用它SomeView.这意味着SomeView应该知道如何布局自己,也就是说,如何在其中放置一些其他视图(您还可以创建一个不使用任何子视图绘制自己的视图,但这超出了普通开发人员的需求).

这种布局是通过[SomeView layoutSubviews].您可以选择覆盖它:

subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ...
// Oh no, I think I didn't do it right.
Run Code Online (Sandbox Code Playgroud)

但你很少需要这样做.在Cocoa Touch的黑暗时代,这种手动布局很普遍,但现在我要说99%的布局可以用自动布局来覆盖.

系统需要知道何时应该呼叫[UIView layoutSubviews].它显然是在您第一次需要绘制视图时完成的,但是每当超视图帧发生变化时也可以调用它.这是一个详细的解释.

所以系统经常打电话[view layoutIfNeeded].也可以随时调用它,但只有当某个事件已经调用[view setNeedsLayout]或者您手动调用它时才会产生效果,就像在这种情况下一样.

约束

自动布局(大写这种方式中的文档),因为你要离开了被称为这样的[SomeView layoutSubviews],因为它是从继承UIView和描述,而不是表示你的子视图的位置约束.

使用自动布局时,系统将[view updateConstraintsIfNeeded]在每个布局过程中执行调用.但是,只有[view setNeedsUpdateConstraints];设置了标志,方法-updateConstraints才会调用(执行实际工作).

如果您不使用自动布局,则这些方法不相关.

您可以像在此示例中一样实现它.

你的榜样

这是很少需要调用 -layoutIfNeeded-updateConstraintsIfNeeded直接,因为UI引擎将在每个布局传球被自动执行.但是,在这种情况下,作者选择立即打电话给他们; 这是因为现在需要产生的高度,而不是将来的某个时刻.

这种更新细胞高度的方法似乎是正确的.请注意,这cell可能是新创建的单元格,因此尚未添加到视图层次结构中; 这不会影响其布局本身的能力.

结论

在自定义视图中,请使用以下选项,从最"通用"到"大多数"自定义:

  1. 在视图创建期间创建约束(手动或在IB中)
  2. 如果以后需要更改约束,请覆盖 -updateConstraints.
  3. 如果具有无法通过上述方式描述的复杂布局,则覆盖-layoutSubviews.

在更改可能使视图约束发生变化的代码中,请调用

[view setNeedsUpdateConstraints];
Run Code Online (Sandbox Code Playgroud)

如果您需要立即获得结果,请致电

[view updateConstraintsIfNeeded]; 
Run Code Online (Sandbox Code Playgroud)

如果代码更改视图的框架使用

[view setNeedsLayout]; 
Run Code Online (Sandbox Code Playgroud)

最后,如果你想立即得到结果,请致电

[view layoutIfNeeded];
Run Code Online (Sandbox Code Playgroud)

这就是为什么在这种情况下需要所有四个呼叫的原因.

其他材料

请查看高级自动布局工具箱文章中的详细说明,objc.io问题#3