Autolayout中Hugging和Compression使用注意

前言

本文主要侧重Autolayout使用过程中,通过代码和SB添加含有intrinsicSize属性控件约束的一些细节。

Hugging和Compression 属性

有很多关于这两个概念的文章,比如stackoverflow上Cocoa Autolayout: content hugging vs content compression resistance priority。我觉得很形象的说明了设置了有什么用,但是还欠缺什么时候使用,即和`intrinsicSize`的关系。先来看下文档上的说明:

- contentCompressionResistancePriorityForAxis:
Returns the priority with which a view resists being made smaller than its intrinsic size.

- contentHuggingPriorityForAxis:
Returns the priority with which a view resists being made larger than its intrinsic size.

这么一看,就很明了:对于有 intrinsicSize 属性的控件(如UILabel,UIButton等),如果当前的frame比显示的content范围大,那么设置的Hugging属性起作用,否则设置的Compression属性起作用。对于相应的数值,越大表明优先级越高,意味着当前的属性占优。简单的说,对于需要Hugging的情形,hugging属性的值越大(优先级越高),那么表明控件需要紧凑的显示。
Hugging和Compression属性值有默认值:

  1. 对于纯代码添加的控件,Hugging默认250.0f,Compression默认 750.0f
  2. 通过SB添加,Hugging默认251.0f,Compression默认750.0f

为什么会有不一样的值?那么先看一下 UILayoutPriority的取值:

static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint.  Do not exceed this.

static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.

static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.

static const UILayoutPriority UILayoutPriorityFittingSizeLevel NS_AVAILABLE_IOS(6_0) = 50;// When you send -[UIView systemLayoutSizeFittingSize:], the size fitting most closely to the target size (the argument) is computed.  UILayoutPriorityFittingSizeLevel is the priority level with which the view wants to conform to the target size in that computation.  It's quite low.  It is generally not appropriate to make a constraint at exactly this priority.  You want to be higher or lower.

由此可见,在设计的时候,iOS的开发人员考虑到类似UILabel的控件首要的是显示所有的内容。

编程实现

通过一段代码,加载一个button:

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.translatesAutoresizingMaskIntoConstraints = NO;
button.backgroundColor = [UIColor redColor];
[button setTitle:@"a long long title" forState:UIControlStateNormal];


[self.view addSubview:button];

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:100.0f];
[self.view addConstraint:constraint];

constraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:100.0f];
[self.view addConstraint:constraint];

constraint = [[NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeWidth multiplier:0 constant:50.0f];
[self.view addConstraint:constraint];

如上添加的constraint,使得button的frame不足以显示标题内容,注意上述constraint默认的优先级都是UILayoutPriorityRequired。因此我们可以通过修改最后一个宽度的constraint:

constraint.priority = UILayoutPriorityDefaultHigh - 1;

对于用SB添加的控件,也可以用类似的方法修改。至于为什么,SB中添加的如UILable的控件,当给其添加某个约束后,SB中Hugging属性的值是251呢?这是为了默认可以显示全内容。此时,你可以在sb中手动把空间尺寸变小,再把控件的某个属性的constriant(width或tailing)的优先级设置为low。这时,你也可以在SB中发现相应的约束由蓝色实线变成了蓝色虚线。当然,如果compression约束起作用的情况下,约束也是蓝色虚线。

与其它控件一起使用

如上单个控件可以正常使用,如果设置一个相邻的控件,会有什么需要注意的吗?答案是NO,什么都不需要操心,仍旧按之前的方法添加约束,这极大的简化了工作量。
另外,这里需要说明的是,需要更新控件上文字的时候,为了有一个较好的动画效果,需要:

[label.superView layoutIfNeeded];

Comments