正确使用 internalContentSize 和 sizeThatFits:在带有自动布局的 UIView 子类上 [英] Proper usage of intrinsicContentSize and sizeThatFits: on UIView Subclass with autolayout

查看:15
本文介绍了正确使用 internalContentSize 和 sizeThatFits:在带有自动布局的 UIView 子类上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问这个(不知何故)简单的问题只是为了挑剔,因为有时我担心我可能会误用许多 UIView 的 API,尤其是在自动布局方面.

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 子类,它有一个图像图标和一个多行标签;我想要的行为是我的视图高度随着标签的高度而变化(以适应里面的文本),此外,我正在使用界面构建器进行布局,所以我有这样的东西:

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; 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:

有一些限制,为图像视图提供固定宽度和高度,并为标签提供固定宽度和位置(相对于图像视图):

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:

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

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. Before autolayout I would have done always something like this:

在 CustoView 子类文件中,我会像这样覆盖 sizeThatFits::

In the CustoView subclass file I would have overridden sizeThatFits: like so:

- (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];

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

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.

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

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.

我正在考虑覆盖 needsUpdateConstraintsupdateConstraints,但仍然没有多大意义,因为我的视图的宽度和高度是从 xib 的自动调整大小掩码推断和转换的.

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.

这么长时间,您认为制作我在这里展示的内容并支持完全自动布局的最干净、最正确的方法是什么?

So long, what do you think is the cleanest and most correct way to make exactly what I show here and support fully autolayout?

推荐答案

我认为你不需要定义一个内在的ContentSize.

I don't think you need to define an intrinsicContentSize.

有两个理由认为:

  1. 当自动布局文档讨论 intrinsicContentSize 时,它提到它与叶视图"相关,如按钮或标签,其中大小可以完全根据其内容计算.这个想法是它们是视图层次树中的叶子,而不是分支,因为它们不是由其他视图组成的.

  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. The idea is that they are the leafs in the view hierarchy tree, not branches, because they are not composed of other views.

IntrinsicContentSize 在自动布局中并不是真正的基本"概念.基本概念只是约束和受约束约束的属性.固有内容大小、内容拥抱优先级和抗压缩优先级实际上只是用于生成有关大小的内部约束的便利.最终大小只是这些约束以通常方式与所有其他约束交互的结果.

IntrinsicContentSize is not really a "fundamental" concept in 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. 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. You can just define the constraints that create the layout you want, and those constraints will also produce the size you want.

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

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. 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? One way is to force layout and then observe the results.

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

Another way is to use systemLayoutSizeFittingSize: (and in iOS8, the little-heralded systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:). This is a closer cousin to sizeThatFits: than is 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.

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

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...

这篇关于正确使用 internalContentSize 和 sizeThatFits:在带有自动布局的 UIView 子类上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆