YongSir

专业程序员伪装者

AutoLayout 的一个重要概念

AutoLayout by YongSir🇨🇳🇨🇳

如果你常常为明明写好了自动布局的代码而得不到想应得效果,特别是在需要按内容自适应的时候,这时候你需要知道一个重要的概念和理解各个布局的优先级问题

  • 内容的压缩阻力内容包裹

    从StackOverFlow上的一个问题开始,还是建议先看原文,毕竟好多老外的词并不是那么好翻译

    what is the content compression resistance and content hugging of UIView?

    Taken from objc.io’s excellent Advanced Auto Layout Toolbox article:

    Intrinsic Content Size

    The intrinsic content size is the size a view prefers to have for a specific content it displays. For example, UILabel has a preferred height based on the font, and a preferred width based on the font and the text it displays. A UIProgressView only has a preferred height based on its artwork, but no preferred width. A plain UIView has neither a preferred width nor a preferred height.

    Compression Resistance and Content Hugging

    Each view has content compression resistance priorities and content hugging priorities assigned for both dimensions. These properties only take effect for views which define an intrinsic content size, otherwise there is no content size defined that could resist compression or be hugged.

    Behind the scenes, the intrinsic content size and these priority values get translated into constraints. For a label with an intrinsic content size of { 100, 30 }, horizontal/vertical compression resistance priority of 750, and horizontal/vertical content hugging priority of 250, four constraints will be generated:

    1
    2
    3
    4
    H:[label(<=100@250)]
    H:[label(>=100@750)]
    V:[label(<=30@250)]
    V:[label(>=30@750)]

    If you’re not familiar with the visual format language for the constraints used above, you can read up about it in Apple’s documentation. Keeping in mind that these additional constraints are generated implicitly helps to understand Auto Layout’s behavior and to make better sense of its error messages.

    Here’s another StackOverflow question that addresses the difference between content compression resistance & content hugging: Cocoa Autolayout: content hugging vs content compression resistance priority

    Quick summary of the concepts:

    • Hugging => content does not want to grow
    • Compression Resistance => content does not want to shrink

    and an example:

    Say you’ve got button like this:

    [ Click Me ]

    and you’ve pinned the edges to a larger superview with priority 500.

    Then, if Hugging priority > 500 it’ll look like this:

    [Click Me]

    If Hugging priority < 500 it’ll look like this:

    [ Click Me ]

    If superview now shrinks then, if the Compression Resistance priority > 500, it’ll look like this

    [Click Me]

    Else if Compression Resistance priority < 500, it could look like this:

    [Cli..]

    If it doesn’t work like this then you’ve probably got some other constraints going on that are messing up your good work!

    E.g. you could have it pinned to the superview with priority 1000. Or you could have a width priority. If so, this can be helpful:

    Editor > Size to Fit Content


其实说的已经很详细了

  • 固有内容大小

    固有内容大小是所显示内容的首选(或者保证显示完整的最小程度)的大小,比如UILabel的固有高度就是当前所用字体(包括字型和字体大小)的首选高度,固有宽度就是当前字体和内容一起决定的首选宽度。UIProgressView的固有内容大小,就只是一个首选的便与完整显示进度条形状的固有高度,而没有一个首选的宽度去决定要显示多长的进度。一个什么都不显示的空白的简易的view是没有首选宽和高的。

  • 压缩阻力内容包裹
    每一个view都分配好的:内容压缩和内容包裹这2个方面的优先级,这两个优先级属性仅仅在决定固有大小时起作用,没有内容时是不起作用的。
    在背后,固有大小和这两个优先级属性值会转化表现为约束(constrains),如对于一个显示着固有内容大小为{100,30}的UILabel来说,水平和垂直的压缩阻力的优先级值为750,内容包裹的优先级为250,所以本质上会转化为:

    1
    2
    3
    4
    H:[label(<=100@250)]
    H:[label(>=100@750)]
    V:[label(<=30@250)]
    V:[label(>=30@750)]

在形象一些了解这些概念:

  • 包裹(Hugging) => 内容不希望再增大
  • 压缩阻力(Compression Resistance) => 内容不希望再压缩

一个有很大的父视图的小btn,上下左右边距都有一定的空隙,并且优先级设为500

1
[       Click Me      ]
  • 如果包裹的优先级 > 500,就会自动包裹,变成这样:

    1
    [Click Me]
  • 如果包裹的优先级 < 500,就不会自动包裹,维持这样:

    1
    [      Click Me      ]

如果父视图现在压缩

  • 如果压缩阻力优先级 > 500,会变成:

    1
    [Click Me]
  • 压缩阻力优先级 < 500, it could look like this:

    1
    [Cli..]

如果没有这两个默认设置的优先级属性,显然在设置布局时我们要处理更多的约束!

所以,在自己添加视图的约束时,要确保子视图的内容压缩阻力和吸附属性约束没有被更高优先级的约束条件覆盖掉,这也是很多时候明明加上了约束而没有起作用的原因。

E.g. you could have it pinned to the superview with priority 1000. Or you could have a width priority. If so, this can be helpful:
Editor > Size to Fit Content