正确使用intrinsicContentSize和sizeThatFits:在具有自动布局的UIView子类上

我问这个(不知何故)简单的问题只是挑剔,因为有时我担心我可能会做很多UIView的API,尤其是当涉及到自动布局的滥用。

为了使它非常简单,我将举一个例子,假设我需要一个具有图像图标和多行标签的UIView子类; 我想要的行为是我的视图的高度随着标签的高度而变化(以适应内部文本),另外,我正在用Interface Builder构build它,所以我有这样的东西:

简单的视图图像

有一些约束给图像视图提供了固定的宽度和高度,固定的宽度和位置(相对于图像视图)到标签:

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

现在,如果我为标签设置了一些文本,我希望视图在高度上resize以适合它,或保持与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; } 

而且我会这样称呼:

 myView.titleLabel.text = @"a big text to display that should be more than a line"; [myView sizeToFit]; 

现在,考虑约束条件,我知道自动布局系统调用视图树元素上的intrinsicContentSize来知道它们的大小并进行计算,因此我应该重写我的子视图中的intrinsicContentSize ,以返回它在sizeThatFits:方法中返回的完全相同的sizeThatFits:以前显示,除了事实上,以前,当调用sizeToFit我有我的看法正确resize,但现在与自动布局,结合xib,这不会发生。

当然,我可能每次在我的子类中编辑文本时,都会调用sizeToFit ,并重载一个重载的intrinsicContentSize ,它会返回sizeThatFits:的完全相同的大小,但不知何故,我认为这不是正确的方法。

我正在考虑重写needsUpdateConstraintsupdateConstraints ,但是仍然没有多大意义,因为我的视图的宽度和高度是从xib的自动调整掩码中推断和翻译的。

很长时间以来,您认为什么是最简洁最正确的方式来完成我在这里展示的内容,并且完全支持自动布局?

我不认为你需要定义一个intrinsicContentSize。

以下是两个原因:

  1. 当自动布局文档讨论intrinsicContentSize ,它将其视为与“叶子视图”(如button或标签)相关的,其中的大小可以纯粹根据其内容进行计算。 这个想法是,它们是视图层次结构树中的叶子,而不是分支,因为它们不是由其他视图组成的。

  2. IntrinsicContentSize在自动布局中并不是真正的“基本”概念。 基本概念只是约束和约束的属性。 intrinsicContentSize,内容拥抱优先级和压缩阻力优先级实际上只是用于产生有关大小的内部约束的便利。 最终的大小只是通常的方式与其他约束相互作用的结果。

所以呢? 所以如果你的“自定义视图”实际上只是一个其他视图的组合,那么你不需要定义一个intrinsicContentSize。 你可以定义创build你想要的布局的约束,这些约束也会产生你想要的大小。

在你描述的特定情况下,我将从标签到超级视图设置一个> = 0的底部空间约束,从图像到超级视图的另一个约束,然后还将视图的高度为零的低优先级约束设置为整个。 低优先级约束将尝试缩小程序集,而其他约束阻止它缩小,以至于它剪辑子视图。

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

另一种方法是使用systemLayoutSizeFittingSize:和在iOS8中,little- systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: 。 这是sizeThatFits:intrinsicContentSize更接近的表亲。 这是系统将用来计算您的视图的适当大小,考虑到它包含的所有约束,包括内在的内容大小约束以及所有其他。

不幸的是,如果你有一个多行标签,你可能还需要configurationpreferredMaxLayoutWidth来获得一个好的结果,但这是另一个故事…