intrinsic content size

为什么UILabel在使用Masonry的时候,不需要给出宽度和高度约束?

自动布局的关键就是给出正确且完整的约束。那么看一下下面的例子给出的例子约束是否完整:

(这里使用Masonry来描述约束,可以参考https://github.com/SnapKit/Masonry,但是我觉得直接看也能够看得懂了)

    UILabel *label = [[UILabel alloc] init];
    label.font = [UIFont systemFontOfSize:15];
    label.text = @"Hello";
    [self.view addSubview:label];
    [label mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view.mas_left).offset(16);
        make.top.equalTo(self.view.mas_top).offset(16);
    }];

这里只定义了两个约束,left 和 top,只够计算出frame的originX和orginY,没有width和height。那么是不是属于不完整的约束呢?其实在这里给出的约束已经是完整的了。因为对于UILabel这个控件而言 ,只要通过其font和text系统就可以计算出Label该有的长度和宽度。这里的长度和宽度就是UILabel的 intrinsic content size(固有属性)。

官方文档给出的视图与intrinsic content size:

一般都是用约束来定义视图的位置和尺寸的。可是,某些视图会根据当前内容生成出一个自然尺寸。这个尺寸即可参考着叫做 intrinsic content size 。比如,一个按钮的 intrinsic content size 就是它的标题加上一个小边缘。

不是所有的视图都有 intrinsic content size,对于普通视图来说,intrinsic content size 可以定义出视图的宽、高或者二者全部。下面的表格3-1中列出了一些示例。

  • 表格 基本控件的 intrinsic content size
视图 真实内容尺寸
UIView和NSView
Sliders 只定义了宽度(iOS)
Labels、buttons、switches和text fields 同时定义了宽度和高度
Text views 和 image views 不同情况下差别很大

intrinsic content size 基于视图的当前内容。一个label或button的 intrinsic content size 基于显示文字的总量和使用的字体。对于其他视图来说,intrinsic content size 可能会更复杂。例如,一个空的image view没有 intrinsic content size。一旦在上面添加图片之后,它的 intrinsic content size 就被设置为图片的尺寸了。

一个text view的 intrinsic content size 有多种不同情况,取决于其内容、是否可以滑动或者是给它添加的其他约束。比如,当可以滑动时,text view没有 intrinsic content size。当不可滑动时,默认来说视图的 intrinsic content size 基于不换行的文字计算而来。再例,在文字中如果不存在换行,intrinsic content size 会计算出需要的宽和高,并将内容布局为一个单行文字。如果你添加约束指定了text view的宽,intrinsic content size 就会根据此宽度来定义出需要的高度并进行显示。

Autolayout通过对每一个尺寸使用一对约束来表示真 intrinsic content size。抗拉伸约束(content hugging,内容包裹)把视图向内部推以保证它可以优雅地环抱着其内容。抗压缩约束(compression resistance)把视图向外推以便它不会轻易裁剪其内容。

image

在列表3-5中展示的这些约束通过使用不等式来进行定义。这里,IntrinsicHeightIntrinsicWidth常量代表了视图 intrinsic content size 中的宽和高。

  • 列表3-5 抗压缩和抗拉伸约束方程
// 抗压缩
View.height >= 0.0 * NotAnAttribute + IntrinsicHeight
View.width >= 0.0 * NotAnAttribute + IntrinsicWidth

// 抗拉伸
View.height <= 0.0 * NotAnAttribute + IntrinsicHeight
View.width <= 0.0 * NotAnAttribute + IntrinsicWidth

这些约束中的每一个都有自己的优先级。默认来说,视图使用250优先级来定义抗拉伸约束,而使用750优先级来定义抗压缩约束。因此,对于压缩视图来说,拉伸它更加容易。对大多数的控件来说,这都是默认行为。例如,你可以安全地将一个button拉伸到大于它本身的真实内容尺寸;但是,如果你压缩它,则很可能会裁剪其内容。记住,Interface Builder可能会适当修改这些优先级以避免此种情况发生。了解更多信息,请看设置抗拉伸和抗压缩约束的优先级。

尽可能地在布局中多使用视图的 intrinsic content size。它可以让你的布局动态适配视图内容的变化。它还可以减少约束的数量来创建出明确的、无冲突的布局,但是你需要管理该视图的抗拉伸和抗压缩约束(统称为CHCR)的优先级。这里是一些处理 intrinsic content size 的指导建议:

  • 当拉伸一些列视图来填充空间时,如果所有视图都有相同的抗拉伸优先级,此布局就存在歧义了。Autolayout不知道应该拉伸哪个视图。
    一个普遍的例子就是label和text field的组合。一般来说,你想要让text field来拉伸填充额外空间,而label保持它自身的真实内容尺寸。要确保这种情况,要保证text field的水平抗拉伸优先级要低于label。
    实际上,这个例子如此普遍,Interface Builder已经可以自动处理此情况,自动将label的抗拉伸优先级设置为251。如果手动编码进行布局,你需要自己修改抗拉伸优先级。
  • 当一些带有不可见背景的视图(如buttons或labels)被拉伸超过本身 intrinsic content size 时,可能经常会显示出怪异或非预期的布局。导致的实际问题可能并不严重,因为文字直接出现在了错误位置上。要避免这种不必要的拉伸,增加抗拉伸优先级即可。
  • 基准线约束只在那些存在真实内容高度的视图上才有效。如果一个视图被垂直拉伸或压缩,基准线约束便不再正常匹配。
  • 一些视图,如switches,应该总是以 intrinsic content size 进行显示。通过提高CHCR优先级来防止被拉伸或压缩。
  • 避免给视图设置“必须级”CHCR优先级。对于视图来说错误的显示尺寸要比偶然出现的约束冲突要更好。如果一个视图需要一直保持 intrinsic content size,考虑将其设置为“非常高”(999)优先级。这个接近“满级”的优先级统称可以保证视图不被拉伸或压缩,而且还可以提供出一个紧急值,以免你的视图在一个与你期望的优先级不同的环境下显示。

你可能感兴趣的:(intrinsic content size)