关于 AutoLayout 的 Hugging 以及 Compression Resistance

二者都是一个相对值,当有两个元素出现冲突时,根据两个元素中对二者 Priority 设置来决定界面如何显示。 Content Hugging Priority 以及 Content Compression Resistance Priority 都分别包含水平向(Horizontal),垂直向(Vertical)两个方向单独设置。

Content Hugging Priority

Content Hugging Priority 是关于"是否将内容拉伸"的选项,当元素出现冲突时,会将Content Hugging Priority 高的一方维持原样,将低的一方拉伸。但此时仍会保持内容的正常显示。

Content Compression Resistance Priority

Content Compression Resistance Priority 是关于“是否将内容压缩”的选项,甚至会压缩到不能正常显示它的内容。当元素冲突时,会将 Content Compression Resistance Priority 低的一方压缩到合适的大小,高的一方尽量维持内容的显示。

应用的🌰

有两个 UILabel 竖排显示。上面的 UILabel 为两行,下面的为三行。当正常显示时是如下的样子:

当将下面的 Label 与下边距设置为8时,二者的正常大小不满足这个布局。所以需要将一方拉伸。这时,Content Hugging Priority 低的一方将被拉伸,高的一方仍正常显示。 2016-08-10 21.09.51

以上是基于布局可以让内容正常显示时的调整,以下则是内容无法正常显示时的调整。当空间小到不足以让两个 UILabel 都正常显示内容时,则会压缩 Content Compression Resistance Priority 低的一方。如下: 2016-08-10 21.10.07

可以看到,下面的 UILabel 与底边距离过长,剩余的空间已经不足以让二者都完整显示了,于是优先保证 Compress Resistance Priority 高的下面的 UILabel 正常显示,而上面的已经被压缩到看不见内容。

总结一下:当布局让元素均可以正常显示内容时,会根据Content Hugging Priority进行调整,高的一方会保持原大小,低的一方会被拉伸。当布局空间不足以让元素正常显示内容时,会根据Content Compression Resistance Priority进行调整,高的一方会保持尽量保持原样,低的一方会被压缩以满足高的一方的显示。

之所以说尽量保持原样,是因为如果空间大小根本不足以让任何一个元素正常显示时,即使是高的那一方也会被压缩,只不过会优先压缩低的那一方,待低的一方已经不能再被压缩时,会再去压缩高的一方。Hugging 拉伸这里我似乎没有想到这种情况? 效果如下: 2016-08-10 21.19.14 如图,可以看到上面蓝色的 Label 已经被压缩不见了,下面灰色的 Label 也被压缩了,仅剩余一点内容。

当不影响内容显示时,怎么调整周围的边距都会去根据 Hugging Priority 进行布局调整的: 2016-08-10 21.10.44

顺便一提,当下面灰色的 Label 与下边距设置从 Equal 变为 Less Than or Equal 时,会保持二者原样的显示: 2016-08-10 21.11.14 因为此时下边距不是硬性的高度,而是小于等于。看来 AutoLayout 还是以让元素正常显示内容为优先的。

关于 UIView 的 intrinsicContentSize

intrinsicContentSize 是一个 view 的固有尺寸,可以把它想象成显示内容所需要的大小。

Content Hugging PriorityContent Compression Resistance Priority 的作用就在于维持 View 的 intrinsicContentSize

UILabel, UIButton 等有自己的大小,所以才会有上文那两个 Label 之间的较量。而普通的 UIView 访问 intrinsicContentSize() 时返回的 CGSize(-1.0, -1.0)。当向上文 UILabel 只指定二者之间的间距以及二者与边框的距离是就会报错。

通过覆盖 UIViewintrinsicContentSize() 即可。

override func intrinsicContentSize() -> CGSize {  
    return CGSize(width: 50, height: 200)
}