在下面的代码中,调用这四种方法进行布局推理.我有点困惑为什么所有这些都是需要的,以及它们彼此不同的做法.它们在过程中用于通过自动布局使单元格的高度变为动态.(来自该库从这个问题.)
[cell setNeedsUpdateConstraints]; [cell updateConstraintsIfNeeded]; [cell.contentView setNeedsLayout]; [cell.contentView layoutIfNeeded];
它来自这个单元格高度的代码块:
- (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; }
但他们的做法有何不同?他们为什么都需要?
假设您将视图逻辑封装在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.
但你很少需要这样做.在Cocoa Touch的黑暗时代,这种手动布局很普遍,但现在我要说99%的布局可以用自动布局来覆盖.
系统需要知道何时应该呼叫[UIView layoutSubviews]
.它显然是在您第一次需要绘制视图时完成的,但是每当超视图帧发生变化时也可以调用它.这是一个详细的解释.
所以系统经常打电话[view layoutIfNeeded]
.您也可以随时调用它,但只有当某个事件已经调用[view setNeedsLayout]
或者您手动调用它时才会产生效果,就像在这种情况下一样.
该自动布局(大写这种方式中的文档),因为你要离开了被称为这样的[SomeView layoutSubviews]
,因为它是从继承UIView
和描述,而不是表示你的子视图的位置约束.
使用自动布局时,系统将[view updateConstraintsIfNeeded]
在每个布局过程中执行调用.但是,只有[view setNeedsUpdateConstraints];
设置了标志,方法-updateConstraints
才会调用(执行实际工作).
如果您不使用自动布局,则这些方法不相关.
您可以像在此示例中一样实现它.
这是很少需要调用 -layoutIfNeeded
和-updateConstraintsIfNeeded
直接,因为UI引擎将在每个布局传球被自动执行.但是,在这种情况下,作者选择立即打电话给他们; 这是因为现在需要产生的高度,而不是将来的某个时刻.
这种更新细胞高度的方法似乎是正确的.请注意,这cell
可能是新创建的单元格,因此尚未添加到视图层次结构中; 这不会影响其布局本身的能力.
在自定义视图中,请使用以下选项,从最"通用"到"大多数"自定义:
在视图创建期间创建约束(手动或在IB中)
如果以后需要更改约束,请覆盖 -updateConstraints
.
如果具有无法通过上述方式描述的复杂布局,则覆盖-layoutSubviews
.
在更改可能使视图约束发生变化的代码中,请调用
[view setNeedsUpdateConstraints];
如果您需要立即获得结果,请致电
[view updateConstraintsIfNeeded];
如果代码更改视图的框架使用
[view setNeedsLayout];
最后,如果你想立即得到结果,请致电
[view layoutIfNeeded];
这就是为什么在这种情况下需要所有四个呼叫的原因.
请查看高级自动布局工具箱文章中的详细说明,objc.io问题#3