所有这些自动布局更新方法有什么区别?都是必须的吗? [英] What is the difference between all these Auto Layout update methods? Are all necessary?
问题描述
在下面的代码中,调用了这四个方法进行布局推理.不过,我有点困惑为什么需要所有这些,以及它们彼此之间的不同之处.它们用于通过自动布局使单元格的高度动态化.(取自 这个存储库 来自 这个问题.)
In the code below, these four methods are called for layout reasoning. I'm a little confused why all of them are needed, though, and what they do differently from one another. They're used in the process to make a cell's height be dynamic with Auto Layout. (Taken from this repository from this question.)
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
它来自这个单元格高度的代码块:
And it's from this block of code for the cell's height:
- (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;
}
但他们的做法有何不同?为什么都需要它们?
But what are they doing differently? Why are they all needed?
推荐答案
Layout
假设您将视图逻辑封装在一个 UIView
子类中,并将其命名为 SomeView
.这意味着SomeView
应该知道如何自己布局,也就是如何在其中放置一些其他的视图(你也可以创建一个不使用任何子视图来绘制自己的视图),但这超出了普通开发人员的需求).
Layout
Suppose you encapsulate your view logic in a UIView
subclass, and call it SomeView
. This means that SomeView
should know how to layout itself, that is, how to position some other views inside it (you can also create a view that draws itself without using any subviews, but that's beyond the needs of an average developer).
此布局由[SomeView layoutSubviews]
完成.您可以选择覆盖它:
This layout is done by [SomeView layoutSubviews]
. You have an option of overriding it:
subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ...
// Oh no, I think I didn't do it right.
但您很少需要这样做.在 Cocoa Touch 的黑暗时代,这种手动布局很普遍,但现在我想说 99% 的布局都可以用自动布局覆盖.
but you rarely need to do so. In the dark ages of Cocoa Touch, this manual layout was widespread, but now I'd say 99% of layouts can be covered with Auto Layout.
系统需要知道什么时候应该调用[UIView layoutSubviews]
.它显然是在您第一次需要绘制视图时完成的,但它也可能在父视图框架更改时调用.这里有详细说明.
The system needs to know when it should call [UIView layoutSubviews]
. It's obviously done the first time you need to draw a view, but it may be also called whenever the superview frame changes. Here's a detailed explanation.
所以系统经常调用[view layoutIfNeeded]
.你也可以在任何时候调用它,但只有当有一些事件调用了[view setNeedsLayout]
或者你手动调用它时才会有效果,就像在这种情况下一样.
So the system often calls [view layoutIfNeeded]
. You can also call it at any time, but this will have an effect only if there is some event that has called [view setNeedsLayout]
or if you have called it manually, as in this case.
自动布局(在 文档) 被这样调用是因为您将 [SomeView layoutSubviews]
保留为它继承自 UIView
和用约束来描述你的子视图的位置.
The Auto Layout (capitalized this way in the documentation) is called like that because you're leaving [SomeView layoutSubviews]
as it is inherited from UIView
and
describe the position of your subviews instead in terms of constraints.
使用自动布局时,系统将在每次布局传递时调用[view updateConstraintsIfNeeded]
.但是,仅当设置了标志 [view setNeedsUpdateConstraints];
时,该方法才会调用 -updateConstraints
(真正起作用).
When using Auto Layout, system will perform calls to [view updateConstraintsIfNeeded]
at each layout pass. However, only if the flag [view setNeedsUpdateConstraints];
is set, the method calls into -updateConstraints
(which does the real job).
如果您不使用自动布局,则这些方法不相关.
If you don't use Auto Layout, those methods are not relevant.
您可以像在本例中那样实现它.
很少需要直接调用 -layoutIfNeeded
和 -updateConstraintsIfNeeded
,因为 UI 引擎会在每次布局时自动执行此操作.然而,在这种情况下,作者选择立即打电话给他们;这是因为现在需要生成的高度,而不是将来的某个时候.
It's rarely necessary to call -layoutIfNeeded
and -updateConstraintsIfNeeded
directly, because UI engine will do that automatically at each layout pass. However, in this case the author has chosen to call them immediately; this is because the resulting height is needed right now, not at some point in the future.
这种更新单元格高度的方法似乎是正确的.请注意,cell
可能是新创建的单元格,因此尚未添加到视图层次结构中;这不会影响其自身布局的能力.
This method of updating the cell's height seems right. Note that cell
could be a newly created cell and thus not added into view hierarchy yet; this does not impact its ability to layout itself.
在您的自定义视图中使用以下选项,从最通用"到最自定义":
In your custom view go with the following options, starting from the most 'universal' to most 'customized':
- 在视图创建过程中创建约束(手动或在 IB 中)
- 如果您稍后需要更改约束,请覆盖
-updateConstraints
. - 如果有无法通过上述方式描述的复杂布局,请覆盖
-layoutSubviews
.
在更改某些内容可能使您的视图的约束发生变化的代码中,调用
In the code that changes something that could make your view's constraints change, call
[view setNeedsUpdateConstraints];
如果您需要立即获得结果,也请致电
If you need results immediately, call also
[view updateConstraintsIfNeeded];
如果代码改变了视图的框架使用
If the code changes view's frame use
[view setNeedsLayout];
最后,如果您想要立即获得结果,请致电
and finally if you want the results immediately, call
[view layoutIfNeeded];
这就是为什么在这种情况下需要所有四个调用.
This is why all four calls are required in this case.
看文章中的详细解释高级自动布局工具箱,objc.io issue #3
Take a look at detailed explanation in the article Advanced Auto Layout Toolbox, objc.io issue #3
这篇关于所有这些自动布局更新方法有什么区别?都是必须的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!