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

时间:2014-06-09 18:57:41

标签: ios objective-c uiview autolayout cgsize

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

为了使它变得非常简单,我将举一个例子,让我们假设我需要一个具有图像图标和多行标签的UIView子类;我想要的行为是我的视图高度随着标签的高度而变化(以适应文本内部),我也用接口构建器进行布局,所以我有这样的东西:

simple view image

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

simple view image, constraints shown

现在,如果我在标签上设置了一些文字,我希望视图在高度上调整大小以适应它,或者保持与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:方法中返回的完全相同的事情,除了事先在调用sizeToFit时我的视图已正确调整大小,但现在使用自动布局,与xib组合,这不会发生。

当然,每当我编辑子类中的文本时,我可能会调用sizeToFit,并且被覆盖的intrinsicContentSize会返回完全相同的sizeThatFits:大小,但不知怎的,我不会&# 39;认为这是正确的做法。

我正在考虑覆盖needsUpdateConstraintsupdateConstraints,但由于我的视图的宽度和高度是从xib的自动调整遮罩推断和转换的,所以仍然没有多大意义。

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

1 个答案:

答案 0 :(得分:67)

我认为您不需要定义intrinsicContentSize。

这有两个理由认为:

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

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

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

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

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

    另一种方法是使用systemLayoutSizeFittingSize:(在iOS8中,这是一个很小的systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:)。这是sizeThatFits:的近亲,而不是intrinsicContentSize。系统将使用它来计算视图的适当大小,同时考虑它包含的所有约束,包括内在内容大小限制以及所有其他约束。

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