在具有autolayout的UIView子类上正确使用intrinsicContentSize和sizeThatFits :.

dev*_*ush 60 objective-c uiview ios autolayout cgsize

我问这个(某种程度上)简单的问题只是为了挑剔,因为有时候我担心我可能会对许多UIView的API进行误操作,特别是在涉及自动布局时.

为了使它变得非常简单,我将使用一个例子,假设我需要一个具有图像图标和多行标签的UIView子类; 我想要的行为是我的视图高度随着标签的高度而变化(以适应文本内部),而且,我正在使用Interface builder进行布局,所以我有这样的事情:

简单的视图图像

使用一些约束来为图像视图提供固定的宽度和高度,并将固定的宽度和位置(相对于图像视图)固定到标签:

简单的视图图像,显示约束

现在,如果我在标签上设置了一些文本,我希望视图在高度上调整大小以适应它,或者保持与xib中相同的高度.在自动布局之前我会做到这样的事情:

在CustoView子类文件中,我会sizeThatFits:像这样重写:

- (CGSize) sizeThatFits:(CGSize)size{

    //this stands for whichever method I would have used
    //to calculate the height needed to display the text based on the font
    CGSize labelSize = [self.titleLabel intrinsicContentSize];

    //check if we're bigger than what's in ib, otherwise resize
    CGFloat newHeight = (labelSize.height <= 21) ? 51: labelSize.height+20;

    size.height = newHeight;

    return size;

}
Run Code Online (Sandbox Code Playgroud)

而且我会称之为:

myView.titleLabel.text = @"a big text to display that should be more than a line";
[myView sizeToFit];
Run Code Online (Sandbox Code Playgroud)

现在,在约束中思考,我知道autolayout系统调用intrinsicContentSize视图树元素来知道它们的大小是什么并进行计算,因此我应该intrinsicContentSize在我的子视图中覆盖它返回它在sizeThatFits:前面显示的方法中返回的完全相同的东西,除了事实上,以前,在调用sizeToFit时我的视图已正确调整大小,但现在使用自动布局,结合xib,这不会发生.

当然,sizeToFit每当我在子类中编辑文本时,我可能会调用,同时重写的intrinsicContentSize返回完全相同的大小sizeThatFits:,但不知怎的,我不认为这是正确的方法.

我在想重写needsUpdateConstraintsupdateConstraints,但仍使没有太大意义,因为我的观点的宽度和高度都推断和从厦门国际银行在自动屏蔽翻译.

这么长时间,您认为最清洁,最正确的方法是如何制作我在这里展示的并完全支持自动布局?

alg*_*gal 72

我认为您不需要定义intrinsicContentSize.

这有两个原因可以考虑:

  1. 当自动布局文档讨论时intrinsicContentSize,它将其称为与"叶子视图"相关,例如按钮或标签,其中大小可以纯粹基于其内容计算.这个想法是它们是视图层次结构树中的叶子,而不是分支,因为它们不是由其他视图组成的.

  2. IntrinsicContentSize在Auto Layout中并不是一个"基本"概念.基本概念只是约束和受约束约束的属性.intrinsicContentSize,内容拥抱优先级和压缩阻力优先级实际上只是用于生成有关大小的内部约束的便利.最终大小只是这些约束以通常方式与所有其他约束交互的结果.

所以呢?因此,如果您的"自定义视图"实际上只是其他几个视图的集合,那么您不需要定义intrinsicContentSize.您可以定义创建所需布局的约束,这些约束也将生成所需的大小.

在您描述的特定情况下,我将从标签到superview设置一个> = 0的底部空间约束,从图像到superview设置另一个约束,然后在视图中设置一个高度为零的低优先级约束作为整个.低优先级约束将尝试缩小程序集,而其他约束阻止它缩小到目前为止它剪切其子视图.

如果您从未明确定义intrinsicContentSize,那么如何看待这些约束产生的大小?一种方法是强制布局,然后观察结果.

另一种方法是使用systemLayoutSizeFittingSize:(在iOS8中,这是一个小小的预测systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:).这是一个更接近表弟sizeThatFits:intrinsicContentSize.系统将使用它来计算视图的适当大小,同时考虑其包含的所有约束,包括内在内容大小约束以及所有其他约束.

不幸的是,如果你有一个多行标签,你可能还需要配置preferredMaxLayoutWidth才能获得好结果,但这是另一个故事......