Rect Transform拥有的布局系统对于各种类型的布局是足够灵活的,并且它也可以让你自由放置元素。但是,有时候更多结构化的东西是需要的。
自动布局系统提供了在嵌套布局组(如水平组、竖直组或者格子组)中放置元素的方法。它还允许元素根据包含的内容量自动调整大小。例如,一个按钮可以根据文本的内容自动缩放大小。
自动布局系统是一个构造在基本Rect Transform布局系统之上的系统。它可以选择性的对一些或全部元素使用。
自动布局系统是基layout elements(布局元素)和layout controllers(布局控制器)的。布局元素是一个含有RectTransform组件和其它可选组件的游戏对象。Thelayout element has certain knowledge about which size it should have.布局元素不能直接设置自己的大小,但是其它作为布局控制器的组件可以使用它们提供的信息用来为它们计算尺寸。
一个布局元素用下列属性来定义自身:
Minimun width(最小宽度)
Minimum height(最小高度)
Preferred width(首选宽度)
Preferred height(首选高度)
Flexible width(灵活宽度)
Flexible height(灵活高度)
使用布局元素提供信息的布局控制器的例子是Content Size Fitter和各种Layout Group组件。在布局组中如何按大小来布局元素的基本原则如下:
最开始只分配最小尺寸;
如果有足够的空间,分配首选尺寸;
如果有额外的空间,分配灵活尺寸;
含有RectTransform组件的任何游戏对象都可以作为布局元素使用。默认它们的最小、首选和灵活尺寸都是0。某些组件添加到游戏对象上后会改变这些布局属性值。
Image和Text组件就是两个会提供布局元素属性值的例子。它们会改变首选宽度和高度以匹配精灵或者文本内容。
如果你想覆盖最小、首选或者灵活尺寸,你可以通过为游戏对象添加一个Layout Element组件来完成。
Layout Element组件可以让你覆盖一个或多个布局属性值。勾选对应控件,然后指定你需要覆盖的数值。
请参看Layout Element参考文档获取更多的信息。
布局控制器一些是用来控制一个或多个布局元素尺寸和位置的组件,它也含有Rect Trasnform组件。一个布局控制器可能控制它的own layout element(自己所在的同一个对象)或者控制child layout elements。
Content Size Fitter用于控制自身布局元素的尺寸。查看自动布局系统执行方式的最简单方法就是增加一个Content Size Fitter组件到含有Text组件的游戏对象上。
如果你将Horizontal Fit或Vertical Fit设置为Preferred Size,Rect Transform组件就会自动调整它的宽或高以适应文本呢内容。
请参看Content Size Fitter相关参考文档。
Aspcet Ratio Fitter用于控制自身布局元素的尺寸。
它可以让高度适应宽度,反之亦然,也可以让元素放在父对象的内部或者包裹父对象。Aspcet Ratio Fitter不会考虑最小尺寸和首选尺寸等布局信息。
请参看Aspect Ratio Fitter相关参考文档。
Layout Group是用来控制子布局元素的大小和位置的控制器。例如,水平的布局组将它的子对象相邻的放置,而格子布局组将它的子对象放在格子里。
布局组不能控制自己的大小。但可以作为一个布局元素被其它控制器控制或者手动设置。
不管布局组如何分配尺寸,大多数时候它都是试图用每一个子布局元素设置的minimum,preferred和flexible尺寸来分配适当数量的空间。布局组也可以任意嵌套。
请参看Horizontal Layout Group, Vertical Layout Group和Gird LayoutGroup相关的参考文档。
因为自动布局系统中的布局控制器会自动控制那些不能通过观察窗口或者场景窗口同时进行手动编辑的UI元素的尺寸和位置。而且这些被改变的值在下一次布局计算时会将被重新设置。
为了解决这个问题,Rect Transform有一个driven properties(被驱动属性)的概念。比如,将HorizontalFit属性设置到Minimum或者Preferred的Content Size Fitter组件会驱动同对象上Rect Transform组件的宽度。这个宽度值变为只读并且在Rect Transform的顶端会出现一个小的信息框告知一个或多个属性值被content Size Fitter驱动。
Rect Transform属性被驱动除了避免手动编辑之外还有其它原因。仅仅是通过改变分辨率或者游戏窗口大小就会引起布局的改变。这反过来会改变布局元素的尺寸和位置,也就会改变被驱动属性的值。但是并不希望仅仅因为改变了游戏窗口的大小就会造成场景被标记为未被保存状态。为了避免这个问题,被驱动属性的值不会和场景一起保存并且他们的改变也不会引起场景数据的改变。
自动布局系统伴随着会使用一些内建的组件,但是它也可能用自定义的方式创建出新的组件来控制布局。这是通过能被自动布局系统的特殊组件接口来实现的。
如果执行了ILayoutElement接口,组件就会被自动布局系统当作一个布局元素来对待。
如果执行了ILayoutGroup接口,组件就会驱动子对象的RectTransform。
如果执行了ILayoutSelfController接口,组件就去驱动自身的Rect Transform。
自动布局系统会按下面的步骤计算并执行布局:
1. 通过调用ILayoutElement组件上的CalculateLayoutInputHorizontal接口计算最小,首选和灵活的宽度。这是按从自下而上的顺序,即子对象比父对象先执行,这样的话,父对象才能拿到子对象的数据以便进行自身的计算;
2. 布局元素的有效宽度被ILayoutController组件上的SetLaytouHorizontal接口计算并设置。这是自上而下进行的,即子对象在父对象之后计算,因为子对象的分配需要根据父对象完整的可用宽度来决定。这一步之后,布局元素的Rect Transform会拥有新的宽度;
3. 计算高度的最小,首选和灵活值,计算方法和第1步类似,只是接口为CalculateLaytouInputVertical;
4. 计算高度的有效值,计算方法和第2步类似,只是接口为SetLaytouVertical。
当组件上的一个属性改变后,会导致当前的布局不再有效,就需要做一个布局的重计算。者会被这个调用触发:
LayoutRebuilder.MarkLayoutForRebuild(transformas RectTransform);
这个重建不会立即发生,而是等到这帧的末尾,也就是渲染之前。不立即执行的理由是因为它会导致在同一帧内地进行多次潜在的布局重建,这会导致性能下降。
会触发重建的时机为:
会改变布局的属性设置器(setters);
这些回调函数种:
OnEnable
OnDisable
OnRectRansformDimensionsChange
OnValidate(只有编辑器状态需要,运行时不用)
OnDidApplyAnimationProperties