Unity3D :自动布局
推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
自动布局
矩形变换布局系统足够灵活,可以处理许多不同类型的布局,还允许以完全自由形式的方式布置元素。但是,有时可能需要更结构化的系统。
自动布局系统提供了将元素放置在嵌套布局组(如水平组、垂直组或网格)中的方法。使用该系统还可以根据元素包含的内容自动调整元素的大小。例如,按钮可动态调整大小来适合其文本内容并加上一些填充。
自动布局系统是建立在基本矩形变换布局系统之上的系统。您可以选择将其用于某些或所有元素。
了解布局元素
自动布局系统基于布局元素和布局控制器的概念。一个布局元素是具有矩形变换以及其他可选组件的游戏对象。布局元素对自身应具有的大小有一定的了解。布局元素不直接设置自身的大小,而是可由用作布局控制器的其他组件使用布局元素提供的信息来计算布局元素要使用的大小。
布局元素具有相应的属性来定义自身的以下参数:
- Minimum width
- Minimum height
- Preferred width
- Preferred height
- Flexible width
- Flexible height
使用布局元素提供的信息的布局控制器组件示例为内容大小适配器 (Content Size Fitter) 以及各种布局组 (Layout Group) 组件。布局组中的布局元素大小设置的基本原则如下:
- 首先分配最小大小。
- 如果有足够的可用空间,则分配偏好大小。
- 如果有额外的可用空间,则分配灵活大小。
任何带有矩形变换的游戏对象都可以作为布局元素。默认情况下,布局元素的最小大小、偏好大小和灵活大小均为 0。某些组件在添加到游戏对象时将更改这些布局属性。
图像 (Image) 和文本 (Text) 组件是提供布局元素属性的两个组件示例。这些组件会更改偏好宽度和高度来匹配精灵或文本内容。
布局元素组件
如果要覆盖最小大小、偏好大小或灵活大小,可通过向游戏对象添加布局元素组件来实现。
使用布局元素组件可以覆盖一个或多个布局属性的值。启用要覆盖的属性的复选框,然后指定要用于覆盖的值。
请参阅布局元素参考页面以了解更多信息。
了解布局控制器
布局控制器是控制一个或多个布局元素(即具有矩形变换的游戏对象)的大小和可能位置的组件。布局控制器可以控制自己的布局元素(其本身所在的同一游戏对象),或者也可控制子布局元素。
用作布局控制器的组件本身也可以同时用作布局元素。
内容大小适配器 (Content Size Fitter)
内容大小适配器充当布局控制器,可用于控制其自身布局元素的大小。查看实际自动布局系统的最简单方法是向带有文本组件的游戏对象添加内容大小适配器组件。
如果将 Horizontal Fit 或 Vertical Fit 设置为 Preferred,则矩形变换将调整其宽度和/或高度以适应文本内容。
请参阅内容大小适配器参考页面以了解更多信息。
宽高比适配器 (Aspect Ratio Fitter)
宽高比适配器充当布局控制器,可用于控制其自身布局元素的大小。
宽高比适配器可以调整高度来适应宽度或反之,也可以使元素在其父项内部适应或包裹其父项。宽高比适配器不考虑布局信息,例如最小大小和偏好大小。
请参阅宽高比适配器参考页面以了解更多信息。
布局组
布局组充当布局控制器,可用于控制其子布局元素的大小和位置。例如,水平布局组将其子项并排放置,而网格布局组将其子项放在网格中。
布局组不控制自身的大小。相反,布局组自身作为布局元素,可由其他布局控制器进行控制或手动设置。
无论分配给布局组的大小如何,在大多数情况下,布局组都将尝试根据其子布局元素报告的最小大小、偏好大小和灵活大小为每个子布局元素分配适当的空间量。布局组也可通过这种方式任意嵌套。
请参阅水平布局组、垂直布局组和网格布局组的参考页面以了解更多信息。
矩形变换驱动属性
由于自动布局系统中的布局控制器可以自动控制某些 UI 元素的大小和位置,因此不应通过 Inspector 或 Scene 视图同时手动编辑这些大小和位置。无论如何,即使更改这些值,布局控制器在下一次布局计算时也会重置这些值。
矩形变换有一个驱动属性的概念可解决这一问题。例如,Horizontal Fit 属性设置为 Minimum 或 Preferred 的内容大小适配器将在同一个游戏对象上驱动矩形变换的宽度。该宽度将显示为只读状态,并且矩形变换顶部的小信息框将指示一个或多个属性由内容大小适配器驱动。
除了防止手动编辑之外,矩形变换使用驱动属性还有其他原因。只需更改 Game 视图的分辨率或大小即可更改布局。这样一来可以改变布局元素的大小或位置,进而改变驱动属性的值。但是,通常不希望仅仅因为调整了 Game 视图的大小就将场景标记为具有未保存的更改。为防止这种情况,驱动属性的值不会保存为场景的一部分,对这些属性的更改也不会将场景标记为已更改状态。
技术细节
自动布局系统内置了一些组件,但也可以创建以自定义方式控制布局的新组件。为此,应让组件实现可由自动布局系统识别的特定接口。
布局接口
如果组件实现 ILayoutElement 接口,则自动布局系统会将该组件视为布局元素。
如果组件实现 ILayoutGroup 接口,则该组件应该驱动其子项的矩形变换。
如果组件实现 ILayoutSelfController 接口,则该组件应该驱动自己的 RectTransform。
布局计算
自动布局系统按以下顺序计算和执行布局:
- 通过在 ILayoutElement 组件上调用 CalculateLayoutInputHorizontal 来计算布局元素的最小宽度、偏好宽度和灵活宽度。此过程以自下而上的顺序执行,即子项的计算先于父项,这样父项可以在自己的计算中参考子项的信息。
- 通过在 ILayoutController 组件上调用 SetLayoutHorizontal 来计算和设置布局元素的有效宽度。此过程自上而下的顺序执行,即子项的计算晚于父项,因为子项宽度的分配需要基于父项中可用的完整宽度。在此步骤之后,布局元素的矩形变换便有了新的宽度。
- 通过在 ILayoutElement 组件上调用 CalculateLayoutInputVertical 来计算布局元素的最小高度、偏好高度和灵活高度。此过程以自下而上的顺序执行,即子项的计算先于父项,这样父项可以在自己的计算中参考子项的信息。
- 通过在 ILayoutController 组件上调用 SetLayoutVertical 来计算和设置布局元素的有效高度。此过程自上而下的顺序执行,即子项的计算晚于父项,因为子项高度的分配需要基于父项中可用的完整高度。在此步骤之后,布局元素的矩形变换便有了新的高度。
从上面可以看出,自动布局系统首先计算宽度,然后计算高度。因此,计算的高度可取决于宽度,但计算的宽度决不能取决于高度。
触发布局重新构建
如果组件上的属性发生变化,并可能导致当前布局不再有效,则需要重新计算布局。可使用以下调用来触发重新计算:
LayoutRebuilder.MarkLayoutForRebuild (transform as RectTransform);
重新构建不会立即发生,而是在当前帧结束时并在渲染之前进行。不立即执行的原因是这样做会导致布局在同一帧期间可能多次重新构建,而这对性能不利。
应按以下准则触发重新构建:
- 在可更改布局的属性的 setter 中进行。
- 在以下回调中进行:
- OnEnable
- OnDisable
- OnRectTransformDimensionsChange
- OnValidate(仅在 Editor 中需要,在运行时不需要)
- OnDidApplyAnimationProperties
由3D建模学习工作室整理翻译,转载请注明出处!