Cocoa Autolayout:内容拥抱与内容压缩阻力优先

Cocoa Autolayout: content hugging vs content compression resistance priority

我在苹果的文档中找不到一个明确的答案,关于cocoa autolayout的内容拥抱和压缩阻力之间的区别。

有人能解释他们的用法和区别吗?


概念的快速总结:

  • 拥抱=>内容不想增长
  • 压缩阻力=>内容不想收缩

还有一个例子:

假设你有一个这样的按钮:

1
[       Click Me      ]

你已经将边缘固定到一个更大的超视图,优先级为500。

然后,如果拥抱优先级大于500,则会如下所示:

1
[Click Me]

如果拥抱优先级小于500,则会如下所示:

1
[       Click Me      ]

如果SuperView现在收缩,那么,如果压缩阻力优先级>500,它将如下所示

1
[Click Me]

否则,如果压缩阻力优先级小于500,则可能如下所示:

1
[Cli..]

如果它不是这样工作的话,那么你可能还有其他一些制约因素在影响你的好工作!

例如,您可以将它固定到具有优先级1000的SuperView。或者你可以有宽度优先权。如果是这样,这可能会有所帮助:

编辑器>大小以适合内容


看看这个关于自动布局的视频教程,他们会仔细解释。

enter image description here


enter image description here

资料来源:@mokagio

内在的内容大小-相当简单,但是具有可变内容的视图知道其内容有多大,并通过这个属性描述其内容的大小。具有内在内容大小的视图的一些明显示例是uiImageView、uiLabels和uiButton。

内容拥抱优先权-此优先权越高,视图抵制的增长就越大,而不是其固有的内容大小。

内容压缩阻力优先级-此优先级越高,视图的收缩阻力越大,小于其内部内容大小。

查看此处了解更多说明:自动布局魔力:内容大小调整优先级


假设你有一个按钮,上面写着"单击我"。那个按钮的宽度应该是多少?

首先,您肯定不希望按钮小于文本。否则,文本将被剪切。这是水平压缩阻力的优先级。

第二,你不希望按钮比它需要的大。像这样的按钮[单击我]显然太大了。你想让按钮"拥抱"它的内容而不需要太多填充。这是水平内容拥抱优先级。对于一个按钮来说,它不如水平压缩阻力优先。


如果是view.intrinsicContentSize.width != NSViewNoIntrinsicMetric,那么auto-layout将创建一个类型为NSContentSizeLayoutConstraint的特殊约束。此约束的作用类似于两个普通约束:

  • 要求具有水平拥抱优先权的view.width <= view.intrinsicContentSize.width的约束,以及
  • 要求view.width >= view.intrinsicContentSize.width具有水平抗压优先权的约束。

在Swift中,使用iOS 9的新布局锚定,您可以设置如下等效约束:

1
2
3
4
5
6
7
let horizontalHugging = view.widthAnchor.constraint(
    lessThanOrEqualToConstant: view.intrinsicContentSize.width)
horizontalHugging.priority = view.contentHuggingPriority(for: .horizontal)

let horizontalCompression = view.widthAnchor.constraint(
    greaterThanOrEqualToConstant: view.intrinsicContentSize.width)
horizontalCompression.priority = view.contentCompressionResistancePriority(for: .horizontal)

同样,如果view.intrinsicContentSize.height != NSViewNoIntrinsicMetric,那么auto-layout会创建一个NSContentSizeLayoutConstraint,它对视图的高度有两个限制。在代码中,它们看起来像这样:

1
2
3
4
5
6
7
let verticalHugging = view.heightAnchor.constraint(
    lessThanOrEqualToConstant: view.intrinsicContentSize.height)
verticalHugging.priority = view.contentHuggingPriority(for: .vertical)

let verticalCompression = view.heightAnchor.constraint(
    greaterThanOrEqualToConstant: view.intrinsicContentSize.height)
verticalCompression.priority = view.contentCompressionResistancePriority(for: .vertical)

在布局运行后,通过打印view.constraints,可以看到这些特殊的NSContentSizeLayoutConstraint实例(如果存在)。例子:

1
2
3
4
5
label.constraints.forEach { print($0) }

// Output:
<NSContentSizeLayoutConstraint:0x7fd82982af90 H:[UILabel:0x7fd82980e5e0'Hello'(39)] Hug:250 CompressionResistance:750>
<NSContentSizeLayoutConstraint:0x7fd82982b4f0 V:[UILabel:0x7fd82980e5e0'Hello'(21)] Hug:250 CompressionResistance:750>


内容拥抱和内容压缩阻力优先权适用于元素,这些元素本质上可以根据进入的内容计算其大小。

来自Apple Docs:

enter image description here


Content hugging priority就像一个橡皮筋,放在一个视图周围。优先级值越高,橡皮筋越结实,它越想拥抱它的内容大小。优先级值可以想象为橡皮筋的"强度"

Content Compression Resistance则是,一个视图"抵制"的程度越来越小。具有较高电阻优先级值的视图是抵抗压缩的视图。