简体   繁体   English

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

[英]Proper usage of intrinsicContentSize and sizeThatFits: on UIView Subclass with autolayout

I'm asking this (somehow) simple question just to be finicky, because sometimes I'm worried about a misuse I might be doing of many UIView's APIs, especially when it comes to autolayout. 我问这个(某种程度上)简单的问题只是为了挑剔,因为有时候我担心我可能会对许多UIView的API进行误操作,特别是在涉及自动布局时。

To make it super simple I'll go with an example, let's assume I need an UIView subclass that has an image icon and a multiline label; 为了使它变得非常简单,我将使用一个例子,假设我需要一个具有图像图标和多行标签的UIView子类; the behaviour I want is that the height of my view changes with the height of the label (to fit the text inside), also, I'm laying it out with Interface builder, so I have something like this: 我想要的行为是我的视图高度随着标签的高度而变化(以适应文本内部),而且,我正在使用Interface builder进行布局,所以我有这样的事情:

简单的视图图像

with some constraints that give fixed width and height to the image view, and fixed width and position (relative to the image view) to the label: 使用一些约束来为图像视图提供固定的宽度和高度,并将固定的宽度和位置(相对于图像视图)固定到标签:

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

Now, if I set some text to the label, I want the view to be resized in height to fit it properly, or remain with the same height it has in the xib. 现在,如果我将一些文本设置到标签上,我希望视图的高度可以调整到适当的大小,或者保持与xib中的高度相同。 Before autolayout I would have done always something like this: 在自动布局之前我会做到这样的事情:

In the CustoView subclass file I would have overridden sizeThatFits: like so: 在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;

}

And than I would have called something like: 而且我会称之为:

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

Now, thinking in constraints, I know that autolayout systems calls intrinsicContentSize on the view tree elements to know what their size is and make its calculations, therefore I should override intrinsicContentSize in my subview to return the exact same things it returns in the sizeThatFits: method previously shown, except for the fact that, previously, when calling sizeToFit I had my view properly resized, but now with autolayout, in combination with a xib, this is not going to happen. 现在,在约束中思考,我知道autolayout系统在视图树元素上调用intrinsicContentSize以了解它们的大小并进行计算,因此我应该在子视图中覆盖intrinsicContentSize以返回它在sizeThatFits:方法中返回的完全相同的内容之前显示的,除了以前的事实,当调用sizeToFit时,我的视图已正确调整大小,但现在使用自动布局,结合xib,这不会发生。

Of course I might be calling sizeToFit every time I edit text in my subclass, along with an overridden intrinsicContentSize that returns the exact same size of sizeThatFits: , but somehow I don't think this is the proper way of doing it. 当然,每当我在子类中编辑文本时,我可能会调用sizeToFit ,以及一个重写的intrinsicContentSize ,它返回完全相同的sizeThatFits:大小,但不知何故我不认为这是正确的方法。

I was thinking about overriding needsUpdateConstraints and updateConstraints , but still makes not much sense since my view's width and height are inferred and translated from autoresizing mask from the xib. 我正在考虑覆盖needsUpdateConstraintsupdateConstraints ,但仍然没有多大意义,因为我的视图的宽度和高度是从xib的自动调整掩码推断和转换的。

So long, what do you think is the cleanest and most correct way to make exactly what I show here and support fully autolayout? 这么长时间,您认为最清洁,最正确的方法是如何制作我在这里展示的并完全支持自动布局?

I don't think you need to define an intrinsicContentSize. 我认为您不需要定义intrinsicContentSize。

Here's two reasons to think that: 这有两个原因可以考虑:

  1. When the Auto Layout documentation discusses intrinsicContentSize , it refers to it as relevant to "leaf-views" like buttons or labels where a size can be computed purely based on their content. 当Auto Layout文档讨论intrinsicContentSize ,它将其称为与“叶子视图”相关,例如按钮或标签,其中大小可以纯粹基于其内容来计算。 The idea is that they are the leafs in the view hierarchy tree, not branches, because they are not composed of other views. 这个想法是它们是视图层次结构树中的叶子,而不是分支,因为它们不是由其他视图组成的。

  2. IntrinsicContentSize is not really a "fundamental" concept in Auto Layout. IntrinsicContentSize在Auto Layout中并不是一个“基本”概念。 The fundamental concepts are just constraints and the attributes bound by constraints. 基本概念只是约束和受约束约束的属性。 The intrinsicContentSize, the content-hugging priorities, and the compression-resistance priorities are really just conveniences to be used to generate internal constraints concerning size. intrinsicContentSize,内容拥抱优先级和压缩阻力优先级实际上只是用于生成有关大小的内部约束的便利。 The final size is just the result of those constraints interacting with all other constraints in the usual way. 最终大小只是这些约束以通常方式与所有其他约束交互的结果。

So what? 所以呢? So if your "custom view" is really just an assembly of a couple other views, then you don't need to define an intrinsicContentSize. 因此,如果您的“自定义视图”实际上只是其他几个视图的集合,那么您不需要定义intrinsicContentSize。 You can just define the constraints that create the layout you want, and those constraints will also produce the size you want. 您可以定义创建所需布局的约束,这些约束也将生成所需的大小。

In the particular case that you describe, I'd set a >=0 bottom space constraint from the label to the superview, another one from the image to the superview, and then also a low priority constraint of height zero for the view as a whole. 在您描述的特定情况下,我将从标签到superview设置一个> = 0的底部空间约束,从图像到superview设置另一个约束,然后在视图中设置一个高度为零的低优先级约束作为整个。 The low priority constraint will try to shrink the assembly, while the other constraints stop it from shrinking so far that it clips its subviews. 低优先级约束将尝试缩小程序集,而其他约束阻止它缩小到目前为止它剪切其子视图。

If you never define the intrinsicContentSize explicitly, how do you see the size resulting from these constraints? 如果您从未明确定义intrinsicContentSize,那么如何看待这些约束产生的大小? One way is to force layout and then observe the results. 一种方法是强制布局,然后观察结果。

Another way is to use systemLayoutSizeFittingSize: (and in iOS8, the little-heralded systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: ). 另一种方法是使用systemLayoutSizeFittingSize:并且在iOS8中,使用了很少的systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: This is a closer cousin to sizeThatFits: than is intrinsicContentSize . 这是sizeThatFits:不是intrinsicContentSize It's what the system will use to calculate your view's appropriate size, taking into account all constraints it contains, including intrinsic content size constraints as well as all the others. 系统将使用它来计算视图的适当大小,同时考虑其包含的所有约束,包括内在内容大小约束以及所有其他约束。

Unfortunately, if you have a multi-line label, you'll likely also need to configure preferredMaxLayoutWidth to get a good result, but that's another story... 不幸的是,如果你有一个多行标签,你可能还需要配置preferredMaxLayoutWidth来获得一个好的结果,但这是另一个故事......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM