Unity 补完计划(四):UGUI-4:LayoutSystem
前言
原本是想继续上一篇的内容梳理 LayoutRebuilder
的源码,但发现布局系统的内容非常多且抽象,如果不结合实际的使用来分析很难理解透彻;且大部分的功能在日常使用 Unity 的过程中出现的频率都非常高,例如 HorizontalLayoutGroup
、VerticalLayoutGroup
、GridLayoutGroup
等等。在我们使用 UGUI 的过程中,经常会被这些布局组件的繁杂属性所困扰,因此这里打算先系统性地介绍一下布局系统的使用,之后再继续 LayoutRebuilder
的源码解析。
LayoutSystem 介绍
Auto Layout System 是基于 Rect Transform Layout System 之上的系统(关于 RectTransform 可以参考 Unity3D RectTransform使用详解:布局、属性、方法、设计),自动调整一个或多个的元素大小、位置、间格,又分为 Layout Controllers(父物件) 与 Layout Elements(子物件) 两部分,一个简单的 Auto Layout 架构如下

Layout Element (子物件)
一个 Layout Element 是一个可以被 Layout Controller 控制的物件,它可以有以下属性:
- Min Width/Height: 最小宽度/高度
- Preferred Width/Height: 首选宽度/高度
- Flexible Width/Height: 弹性宽度/高度
点选UI后,可以在 Inspector 最下方切换为 Layout Properties 看到资讯
Layout Controllers 透过不同的布局方式,取得 Layout Element size 分配子物件,基本原则如下
-
首先分配 Minimum Size
-
如果还有足够空间,分配 Preferred Size
-
如果还有额外空间,分配 Flexible Size
从以下图片可以看出图片宽度的增长方式:

首先分配 Minimum Size (300,红色部分);如果还有足够空间,分配 Preferred Size (300~500,绿色部分);如果还有额外空间,分配 Flexible Size:1 (500~700,蓝色部分)
比较特别的是 Flexible,他是代表著整个大小的比例,如果 Layout 下有2个物体,分别给 Flexible 设定为 0.3 与 0.7,那比例就会变成下图 (3:7)

另外要注意的是,Text、Image Component 会根据内容大小自动分配 Preferred Size。
Layout Controller (父物件)
Layout Group
不会控制 Layout Controllers (父物件)自身大小,而是控制子物件大小与位置,在大多数情况下,根据每个元素的 minimum、preferred、flexible 大小分配适当的空间,layout group 之间也可以嵌套,又分为 Horizontal(水平)、Vertical(垂直)、Grid(格状) 3种。
Horizontal Layout Group
Horizontal Layout Group 组件的可配置属性如下:
-
Padding:填充内部空间
-
Spacing:每个元素间格
-
Child Alignment:当没有填满全部空间时,子物件对齐位置
-
Child Force Expand:强制控制子物件填满空间
以一个例子来说明各参数的含义,这里我们为父物体添加一个 Horizontal Layout Group 组件,然后在其下添加多个 button,完成后如下,当大小改变时会自动分配子物件大小。
-
Layout Group 的 Padding 与 Spacing
此时在 Button 的 Rect Transform Component 就不能进行调整,因为我们已经透过 Horizontal Layout Group 进行分配空间,在 Rect Transform 会显示目前被哪个 Layout Group 控制
将 Padding 数值调整如图,可以看出填充区域
将 Spacing 数值调整如图,可以看出元素区间
-
Layout Element 的 Min Width
接下来我们将5个 Button 增加 Layout Element Component 覆盖预设大小,用于手动设定每个元素的大小。此时将 Horizontal Layout Group 的 Child Force Expand Width 取消勾选,不强制子物件填满额外空间,而是透过 Layout Element 手动设定。这里使用几种不同的设定,来理解 Horizontal Layout Group 是怎么取得 Layout Element size 分配子物件。
将 5个 Button 的 Layout Element Min Width 分别改为 20、30、40、50、60,此时可以看出每个 Button 宽度分布,改变父物件大小时子物件大小并不会改变,因为只有分配 Min Width,并不会分配额外有效空间。
此时改变 Horizontal Layout Group 的 Child Alignment,可以看出元素对齐
父物件 Layout Properties Min Width = 5个按钮宽(20 30 40 50 60=200) Spacing(40) Padding Left、Right(20) = 260
-
Layout Element 的 Preferred Width
现在将第1个 Button 的 Layout Element 数值调整如图
父组件首先分配 Minimum Size(20),空间足够的情况下,将会分配剩下的 Preferred Size (20~100 空间),如下所示。
-
Layout Element 的 Flexible Width
现在将第1个 Button 的 Layout Element 数值调整如图
父组件首先分配 Minimum Size(20),空间足够的情况下,将会分配剩下的 Preferred Size (20~100 空间),如果还有额外空间,将会分配 Flexible Size,如下所示。
-
Layout Group 的 Child Force Expand
现在将 Horizontal Layout Group 的 Child Force Expand Width 勾选,让子物件强制填满。
父组件首先分配 Minimum Size(20),空间足够的情况下,将会分配剩下的 Preferred Size (20~100 空间),如果还有额外空间,将会分配 Flexible Size 与 Child Force Expand Width,如下所示。
小结:
上面我们看到,所有元素会先被分配 Minimum Size,接下来还有足够空间,将会分配剩下的 Preferred Size,最后才是 Flexible Size 与 Child Force Expand Width。至此我们了解到 Horizontal Layout Group 是如何为子物件分配空间的,Vertical Layout Group 与 Grid Layout Group 也是类似的,只是方向与分配方式不同,这里就不再赘述。
Grid Layout Group
Grid Layout Group 是一个网格布局组件,可以让子物件按照网格排列,其可配置属性如下:
-
Padding:填充内部空间
-
Cell Size:每个元素大小
-
Spacing:每个元素的间隔
-
Start Corner:起始角落,分为左上、右上、左下、右下,决定元素排列的起始位置。注意观察元素的数字
- Start Axis:起始轴,分为水平、垂直,决定元素排列的方向。注意观察元素的数字
-
Child Alignment:当没有填满全部空间时,子物件对齐位置
-
Constraint:约束,分为 Flexible、Fixed Row Count、Fixed Column Count 3种,决定元素排列的方式
-
Flexible:自由排列,根据 Cell Size 与 Spacing 自由排列元素
-
Fixed Row Count:固定行数,根据 Row Count 与 Cell Size 与 Spacing 排列元素
-
Fixed Column Count:固定列数,根据 Column Count 与 Cell Size 与 Spacing 排列元素
-
Content Size Fitter
上面我们介绍了 Layout Group,该组件会根据父物体的大小,自动调整子物体的大小与位置,但是有时候我们需要根据子物体的大小,自动调整父物体的大小,这时候就需要 Content Size Fitter 组件。
Content Size Fitter 组件的可配置属性如下:
-
Horizontal Fit:水平适配,分为 Unconstrained、Min Size、Preferred Size、Max Size 4种,决定水平方向的适配方式
-
Vertical Fit:垂直适配,分为 Unconstrained、Min Size、Preferred Size、Max Size 4种,决定垂直方向的适配方式
其中,Unconstrained 代表不适配,Min Size 代表以子物体最小大小适配,Preferred Size 代表以子物体首选大小适配。
下面我们以一个例子来说明 Content Size Fitter 的使用:
首先我们在 Canvas 下创建一个父物体,然后添加 Horizontal Layout Group 组件,这时如果在父物体下添加 Button,可以看到在 Horizontal Layout Group 的控制下,子物体会自动排列并调整大小,而父物体本身的大小并不会改变:
我们为 Button 们添加 Layout Element 组件,然后调整 Min Width 以覆盖预设大小。接下来我们为父物体添加 Content Size Fitter 组件,将 Horizontal Fit 调整为 Min Size。
可以看到父物体的大小会根据子物体的最小大小自动调整:
这样的设置就可以满足父物体根据子物体大小自动调整的需求。
此外,通过调整父物体的 Pivot,还可以控制父物体的缩放方向,如下图所示:
Aspect Ratio Fitter
Aspect Ratio Fitter 组件可以根据子物体的宽高比例,调整父物体的大小,其可配置属性如下:
- Aspect Mode:
-
None:不调整
-
Width Controls Height:宽度控制高度
以 Width 为基准,依据 Aspect Ratio 调整 Height
当 Width 改变时,Height 会依比例改变
-
Height Controls Width:同理,以 Height 为基准,依据 Aspect Ratio 调整 Width
-
Fit In Parent:适应父物体
依据比例将 宽高、位置、anchors 自动调整,使此图形大小在父物件中完全贴齐,此模式可能不会包覆所有空间。
当子物体的比例与父物体相同时,会完全贴齐;当子物体的比例与父物体不同时,会按比例缩小子物体。
调整父物件大小,物体会依据比例贴齐父物件
-
Envelope Parent:包裹父物体
依据比例将 宽高、位置、anchors自动调整,使此图形大小完全包覆父物件,此模式可能会超出空间。
当子物体的比例与父物体相同时,会完全包裹;当子物体的比例与父物体不同时,会按比例放大子物体。
调整父物件大小,物体会依据比例包裹父物件
总结
至此我们就分析完了 Auto Layout System 的基本使用,通过 Layout Group、Content Size Fitter、Aspect Ratio Fitter 等组件,我们可以很方便地实现 UI 的自动布局,这些组件在我们日常使用 Unity 进行 UI 开发时会经常用到,掌握这些组件的使用,可以让我们更高效地进行 UI 开发。
在下一篇文章中,我们将继续分析 LayoutRebuilder 的源码,了解其是如何实现 UI 的自动布局的。