之前说到自动布局的关键就是给出正确且完整的约束。那么看一下下面的例子给出的例子约束是否完整:
(这里使用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:
View | Intrinsic content size |
---|---|
UIView and NSView | No intrinsic content size. |
Sliders | Defines only the width |
Labels, buttons, switches, and text fields | Defines both the height and the width. |
Text views and image views | Intrinsic content size can vary. |
那么对于具有intrinsic content size的视图来说,是不是意味着自动帮该这些视图添加了像width=a,height=b这样的约束呢?
这里,其实在布局的时候会添加四个约束(对于height 和 width均有intrinsic size的情况下):
// Compression Resistance
View.height >= IntrinsicHeight
View.width >= IntrinsicWidth
// Content Hugging
View.height <= IntrinsicHeight
View.width <= IntrinsicWidth
compression resistance
2,3为抗压缩约束,防止视图被压缩,约束默认的优先级为750(UILayoutPriorityDefaultHigh)。设置的API为:
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis
axis参数表示方向,水平或者垂直。
content hugging
6,7约束防止视图被拉伸,约束的默认优先级为250(UILayoutPriorityDefaultLow)。设置的API为:
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis
应用
一般我们会如何运用compression resistance 和 content hugging呢?
给出一个比较常见的需求:
在同一行中显示标题和时间,时间必须显示完全,标题如果太长就截取可显示的部分,剩余的用…表示。
代码如下:
UILabel *titleLabel = [[UILabel alloc] init];
[self.view addSubview:titleLabel];
titleLabel.text = @"Each of these constraints can have its own priority. By default, ";
[titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view.mas_left).offset(16);
make.top.equalTo(self.view.mas_top).offset(100);
}];
UILabel *timeLabel = [[UILabel alloc] init];
timeLabel.text = @"2017/03/12 18:20:22";
[self.view addSubview:timeLabel];
[timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(titleLabel.mas_right).offset(8);
make.top.equalTo(titleLabel.mas_top);
make.right.lessThanOrEqualTo(self.view.mas_right).offset(-8);
}];
// [timeLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
最后一句被注释的结果:
去掉注释后的结果:
这是因为去掉注释后,timeLabel的水平抗压缩约束的优先级(required,1000)高于titleLabel的优先级(750)。所以这里被压缩的是titleLabel。同理也可应用于content hugging,只是将方向方向改变一下。