我问这个(不知何故)简单的问题只是为了挑剔,因为有时我担心自己可能会误用许多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;

}

然后我会称之为:

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

现在,在约束中思考,我知道autolayout系统调用视图树元素上的intrinsicContentSize,以了解它们的大小并进行计算,因此我应该在子视图中重写intrinsicContentSize,以返回与之前显示的sizeThatFits:方法中返回的完全相同的内容,除了以下事实:,当我打sizeToFit时,我的视图被适当地调整了大小,但现在有了autolayout,再加上一个xib,这是不会发生的.

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

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

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

推荐答案

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

有两个理由认为:

  1. 当Auto Layout文档讨论intrinsicContentSize时,它将其称为与"叶视图"相关,例如按钮或标签,在这些按钮或标签中,可以纯粹根据其内容计算尺寸.它们是视图层次树中的叶子,而不是分支,因为它们不是由其他视图组成的.

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

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

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.

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

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

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

Objective-c相关问答推荐

日期更改时的 UIDatePicker

如何通过仅更改高度而不更改宽度来调整 UILabel 的大小?

Xcode 预处理器输出

定义缓存变量时在objective-c中使用static关键字

iOS performSelectorOnMainThread 有多个参数

使用 UIScrollView 用两根手指滚动

与 iOS 6.0 原生 Facebook 集成共享:通过我的应用名称发布?

UITextField 中的文本在编辑后向上移动(编辑时居中)

如何调整 UIModalPresentationFormSheet 的大小?

Interface Builder 中的 IBOutletCollection 集排序

判断 NSInteger 是奇数还是偶数

设置数据后调整 UICollectionView 单元格的大小

WKWebView 判断 JavaScript 返回值

强制iphone应用程序以编程方式重新启动?

UILabel 根据要显示的文本自动调整大小

通过将另一个字符串重复给定次数来创建 NSString

使用 cocoaLumberjack 将日志(log)文件存储在哪里

如何更新 Core Data 中的现有对象?

围绕其中心旋转 UIView 保持其大小

在 iOS 8 中使用 NSMutableAttributedString 的字符串的下划线部分不起作用