本文分享Unity中的自动布局(AutoLayout)
在大部分情况下, Unity提供的RectTransform 已经足够应付我们日常遇到的需求, 我们一般通过手动修改RectTransform 即可.
但是在有些情况下, 我们需要动态设置RectTransform , 特别是动态调整大小或者一些组合布局的需求.
Unity给我们提供了满足这种需求的机制, 就是所谓自动布局.
自动布局的基本介绍
自动布局由两部分组成, 即布局元素(LayoutElements )和布局控制器(LayoutControllers ).
布局元素本身并不会对RectTransform 做任何修改, 需要由布局控制器来根据自身的性质和布局元素的值来设置.
布局控制器分为控制自身的和控制子节点两类.
不管是自身还是子节点, 被控制器控制之后无法手动修改RectTransform , 有些是不能修改位置, 有些是不能修改大小, 视具体的控制器而定, 如图被控制了位置和高度:

如果父节点同时拥有控制自身的和控制子节点的控制器, 因为此时子节点由父节点控制, 所以子节点不能拥有控制自身的控制器:

布局元素(LayoutElement)
布局元素指实现了接口ILayoutElement 的组件或者拥有布局元素的对象.
如果拥有多个布局元素组件, 根据layoutPriority 确定优先级, 比如Image 为0, InputField 为1, 同时存在时, 会优先使用InputField 的属性.
布局元素相关的组件有:

属性说明
布局元素实现接口后, 将会拥有以下属性, 并在属性面板最下方通过切页显示, 并在属性面板最下方通过切页显示:
   
说明
Min Width/Height : 最小大小Preferred Width/Height : 首选大小, 根据元素内容得到的最适合大小Flexible Width/Height : 灵活大小, 相对单位大小, 默认情况下不启用LayoutElement 组件: 默认情况下布局元素会自动调节属性, 如果不满意可以通过添加LayoutElement 组件手动调节
IgnoreLayout : 忽略自动布局, 将当前布局元素声明为非布局元素, 忽略自动布局的影响Layout Priority: 同一个元素可以添加多个LayoutElement 组件, 根据此属性可以调节组件之间的优先级, 值越大优先级越高
布局控制器(LayoutControllers)
布局控制器是指实现了接口ILayoutController 的类, 类图如下

控制器的分类
控制器根据控制的对象可以分为控制自身和控制子节点的类型.
控制自身大小和位置(RectTransforms )
实现了ILayoutSelfController 接口的类:
AspectRatioFitter : 宽高比适配器, 根据Aspect Mode属性选择适当的模式来适配自身的大小, 忽略布局元素的值.ContentSizeFitter : 内容大小适配器, 使用布局元素的最大/最小值或者偏好大小来确定自身的大小.
- 可以指定水平或者垂直方向上的适配方式来控制宽度和高度
Horizontal Fit/Vertical Fit
None : 不控制Minimum : 根据布局元素的最小值Preferred : 根据布局元素的偏好值
控制子节点大小和位置(RectTransforms)
实现了ILayoutGroup 接口的类:
-
GridLayoutGroup : 网格布局, 子节点被称为Cell, Cell大小和位置固定由空间驱动, Cell的LayoutElement 无效 -
水平布局或者垂直布局: 此类控制器默认只能控制子节点的位置, 如果需要根据子节点的布局元素类控制需要设置Child Controls Size
HorizontalLayoutGroup : 水平布局VerticalLayoutGroup : 垂直布局- 属性说明
Child Alignment : 确定子节点的排序Child Controls Size : 通过子节点的布局元素来确定子节点的大小- Child Force Expand: 如何处理父节点的剩余部分
Child Controls Size 勾选时(这里子节点针对布局元素, 决定位置和大小): 在满足各个子节点的PreferredSize 后, 剩余的部分Size由各个子节点填充, 填充如下
- 将所有子节点的
FlexibleSize 加起来为TotalFlexibleSize, 如果子节点没有设置FlexibleSize , 那么默认为1 - 剩余的部分Size除以TotalFlexibleSize获得平均FlexibleSize的大小
- 子节点根据自身
FlexibleSize 乘以平均FlexibleSize的大小获得填充大小 Child Controls Size 未勾选时(这里子节点针对所有RectTransform 元素, 决定位置): 按照所有的子节点RectTransform 的大小排列之后, 多余的部分当做间隔平分填充到子节点之间
使用示例
下面给出两个比较常见的需求, 作为上述理论的实践.
(1)Text 内容自适应
需求说明: 默认情况下Text 的大小需要手动指定, 我们想要固定宽度或者高度, 让另一个方向根据内容自动调整.
Text 实现了ILayoutElemtent 接口, 是一个布局元素, 默认情况下:
Min Width/Height 为0Flexible Widht/Height 不生效- 根据当前内容和当前
RectTransform 的值计算适合的PreferredSize - 此时布局元素的属性不影响
RectTransform  
添加控制器ContentSizeFitter , 调节自身大小为首选大小:
 
(2)由子节点大小动态确定父节点的大小
需求: 某些情况下, 一些容器类型的对象, 我们希望其大小是根据子节点大小动态变化的, 比如ScrollView 的Content 动态扩容.
解决思路: Content 需要控制自身大小, 也需要控制子节点大小:
- 控制子节点大小: 根据子节点的布局元素属性来设置子节点大小(首选和最小都可以)
- 控制自身大小: 子节点的大小设置完成后, Content的首选大小会被正确的设置, 之后我们可以使用
ContentSizeFitter 来选择首选大小控制自己的大小即可
具体步骤演示:
|