☰
Unity UGUI布局组件(LayoutGroup、ContentSizeFitter、LayoutElement)详解
2026/11/4 19:47:02 网站建设 项目流程

UGUI 自动布局是一套基于接口、分两轮四阶段、脏标记延迟批量执行的 C# 排版系统,和 Transform 原生锚点完全隔离; 所有布局组件都围绕两个接口:

  1. ILayoutElement:提供尺寸信息(min/preferred/flexible),回答 “我应该多大”
  2. ILayoutController(ILayoutGroup):收集子元素尺寸、分配空间、写 RectTransform,负责 “把大家摆到哪”Unity

三个组件分工:

  • LayoutElement:数据提供者,覆盖 / 声明自己的布局尺寸参数(优先级最高)
  • LayoutGroup(Vertical/Horizontal/Grid):既是 ILayoutElement(对外输出自己整体尺寸),又是 ILayoutController(控制子物体位置大小)
  • ContentSizeFitter:只做 ILayoutController,只读同物体上 ILayoutElement 的尺寸,修改自身 RectTransform 大小,不控制子物体

整套布局不生成 Mesh、不渲染;最终输出只有对 RectTransform 的sizeDelta/anchoredPosition的赋值。

LayoutElement

LayoutElement 是 ILayoutElement 的实现,只负责向外输出尺寸信息,不摆放物体、不修改 RectTransform 位置;用来覆盖 / 重写 Text、Image、LayoutGroup 自带的 min/preferred/flexible 尺寸。

面板逐项解释

1. Ignore Layout

勾选之后:布局系统直接跳过这个物体,不参与父 LayoutGroup 的排版计算。

这个物体还留在层级里,渲染正常

2. Min Width / Min Height(最小宽高)

勾选激活,填写像素值

这个元素被压缩时,不能小于这个尺寸,是底线。

3. Preferred Width / Preferred Height(期望 / 偏好宽高)

勾选激活,填写像素值

元素最理想、刚刚好的尺寸。 空间足够、满足所有 Min 之后,布局系统会尽量把元素给到 Preferred 尺寸。

4. Flexible Width / Flexible Height(弹性宽高)

勾选激活,填写比例系数(不是像素!)

当父 LayoutGroup 分配完所有 Min+Preferred 之后,还有剩余空白空间,就按照所有子 Flexible 的比值瓜分剩下空间。

例子: 水平布局里两个子:A Flexible Width=1,B Flexible Width=2

剩余空间一共 300px → A 拿 100,B 拿 200。

只要任意一个子 Flexible>0,剩余空间就会被瓜分;全部 0,就不会拉伸填充。

区分:Min、Preferred 是像素单位;Flexible 是相对权重。

5. Layout Priority(布局优先级,默认 1)

同一个 GameObject 身上,可能有多个 ILayoutElement(比如 Text + LayoutElement)

  • 数值越大优先级越高;布局系统优先读取高优先级组件输出的尺寸,覆盖低优先级;
  • Text、Image 原生的 LayoutPriority 默认是 0;LayoutElement 默认是 1。

这就是为什么挂上 LayoutElement 勾选 Preferred,会直接覆盖 Text 文字原生自适应尺寸!LayoutElement 优先级更高。

  • 如果优先级相同,布局会取各个组件里更大的尺寸值。

注意理解!!!

LayoutElement 这个组件本身,挂在物体上不需要 “必须有父物体”;但是!它的功能想要生效,就必须有父级的布局控制器(ILayoutController)

布局控制器 = HorizontalLayoutGroup / VerticalLayoutGroup / ContentSizeFitterLayoutElement 的角色:对外上报尺寸数据(min/preferred/flexible)

布局控制器的角色:读取子物体上报的这些尺寸数据,然后去排版、改子物体 RectTransform

1. 单纯挂上 LayoutElement(没有父 Layout 控制器)

你可以随便挂,不会报错,组件面板正常显示

完全没有任何视觉效果,等于白挂

原因:LayoutElement 只是一个数据记录本 。它只会存:我的最小宽 30、期望宽 100、弹性权重 1……但是没有任何东西来读这份记录,就不会有人根据这个数据修改物体大小、位置。

2. 有父布局控制器的时候(这才是 LayoutElement 的正常用法)

LayoutElement 是给【直接父 LayoutGroup】读的不是随便哪个祖先,是直属父物体!

3. 一个特殊情况:同物体身上搭配 ContentSizeFitter

LayoutElement 和 ContentSizeFitter 在同一个物体上,不需要别的父 Layout!

这个场景下,不需要外面再套一个父 LayoutGroup!

作用:用 LayoutElement 强行指定这个物体的 preferred 尺寸,ContentSizeFitter 把自己缩放到这个 preferred 大小。

4. 再单独说 Ignore Layout(LayoutElement 里这个选项特殊)

Ignore Layout 生效条件:

这个物体,必须是某个 LayoutGroup 的直接子物体

父 LayoutGroup 遍历直接子的时候,看到子勾选 Ignore Layout → 跳过它,不参与排版。

如果它根本不是任何 LayoutGroup 的子,Ignore Layout 这个勾,勾了也没用。

Flexible 填 1 不等于占 100%,是比值,必须多个兄弟一起对比;

LayoutPriority 是同一个物体多个 ILayoutElement 之间的优先级,不是兄弟物体之间的优先级

三个 LayoutGroup

Grid Layout Group/Horizontal Layout Group/Vertical Layout Group都是ILayoutController(布局控制器),作用:自动排列自己的直接子物体。

  • Horizontal(水平):一排横向摆放,会读取子 LayoutElement 的 Min/Preferred/Flexible(弹性生效)
  • Vertical(垂直):一列纵向摆放,会读取子 LayoutElement 的 Min/Preferred/Flexible(弹性生效)
  • Grid(网格):格子布局,固定 CellSize,无视子的 Min/Preferred/Flexible(LayoutElement 尺寸除 Ignore Layout 外全部无效)

Horizontal Layout Group 水平布局组(横向一排排列子物体)

Padding内边距。

Spacing子物体和子物体之间的间距(横向间隔)。

Child Alignment在父容器里怎么对齐

Reverse Arrangement反向排列

Control Child Size控制子尺寸(重点!)

  • 勾选Height,代表:父 LayoutGroup 接管子物体高度,子物体 RectTransform 的高度直接被引擎锁死、不能手动拖拽改。

勾选之后,子多高多宽由父说了算,子自己 LayoutElement 尺寸规则失效。

Use Child Scale使用子缩放

是否把子物体 RectTransform 的 Scale 算进布局计算里。 一般不勾。如果你的子要动态缩放 UI,再开启,容易排版错乱。

Child Force Expand子强制扩展(弹性总开关,超级高频!)

Width:开启横向弹性通道。 勾选✔后:如果子没有自己设置 Flexible,布局默认给所有子 Flexible=1,平分剩余空间; 子自己 LayoutElement 写了 Flexible,就按写的权重瓜分剩余空白

不勾:Flexible 完全失效,不会自动撑满

Height:纵向弹性,一般很少开。

Vertical Layout Group 垂直布局组(纵向一列排列子物体)

参数和 Horizontal 几乎一模一样,只是排列方向从上往下。

Grid Layout Group 网格布局(格子布局,重点,和上面两个本质不一样!)

核心区别:Grid 不读取子的任何 Min/Preferred/Flexible,LayoutElement 尺寸设置无效!Grid 逻辑:我规定每个格子多大(Cell Size),所有子强制塞进格子里。

Padding:网格整体离父容器四边的内边距

Cell Size(网格核心)

每个格子的宽和高。这里是 100×100:所有子都会被强制放到 100×100 的格子里面。 子物体 Rect 会被 Grid 自动设置成这个尺寸,无视 Image/TMP/LayoutElement 想要的大小。

Spacing

格子与格子之间的间距:X 横向格子间距,Y 纵向格子间距。

Start Corner起始角落

从哪个角落开始放第一个子:Upper Left 左上 / Upper Right 右上 / Lower Left 左下 / Lower Right 右下。

Start Axis起始轴

Horizontal:优先先排满一行,再换行(一行放多个,再下一行,最常用)

Vertical:优先先排满一列,再换列(一列放满再往右开新列)

Child Alignment

整组网格在父容器里怎么对齐

和锚点有关系吗?

Grid Layout Group 不但不读子物体的锚点,还会强行把所有子物体的锚点改成同一个值——左上角(0, 1)

由 GridLayoutGroup 驱动的部分参数

Constraint 约束模式(控制一行多少个 / 一列多少个,非常常用)

  1. Flexible(你当前这个):自动适配根据父容器宽度,自动算一行能放下几个格子,父拉宽一行格子变多,父变窄一行变少。适合动态网格商品、图标。

  2. Fixed Column Count:固定列数,比如填 3 →永远一行 3 个,不管父多宽,自动缩放格子间距 / 换行。

  3. Fixed Row Count:固定行数,比如填 2 → 永远一共 2 行。

Grid 里面子身上的 LayoutElement:

  • Ignore Layout 正常生效:勾选后这个子不参与网格排版,自由摆放

  • Min / Preferred / Flexible 全部无效!Grid 强制 CellSize,不走那套分配算法。

Content Size Fitter(内容尺寸适配器)

ContentSizeFitter(简称 CSF)是让自己这个物体的 Rect 大小,去贴合它内部内容的 Preferred 尺寸

LayoutGroup(Horizontal/Vertical/Grid)是父管子:父来安排子的位置大小

CSF 是自己管自己:自己根据内部内容,自动改变自身宽高 它也是布局控制器ILayoutController

Parent has a type of layout group component. A child of a layout group should not have a Content Size Fitter component, since it should be driven by the layout group.

父物体是 LayoutGroup(Horizontal/Vertical/Grid),这个子物体不建议挂 ContentSizeFitter;子的尺寸应该由父 LayoutGroup 来驱动控制。

为什么 Unity 给这个警告?

这里出现了两个控制器抢着控制同一个 RectTransform

  • 父:HorizontalLayoutGroup,它想决定这个子有多宽、放哪里(父 Layout 来分配空间)
  • 子:ContentSizeFitter,它又想自己决定自己的宽高(我要贴合我内部内容) 两个布局引擎同时驱动同一个 Rect →布局循环冲突,容易抖动、计算错乱、编辑模式闪、Play 模式尺寸随机

分两种情况理解,不是绝对不能用,是容易踩坑

情况 A:不推荐、警告的结构

父:HorizontalLayoutGroup(父要分配子的尺寸) └──子:Image/TMP + ContentSizeFitter(子又想自己控制自己大小)

Unity 警告。 能不能跑?有时候能跑,但是不稳定,布局循环风险很高,不推荐这么写。

情况 B:标准、安全、推荐的 CSF 用法,不会警告

CSF 放在LayoutGroup 自己身上!

物体A:VerticalLayoutGroup + ContentSizeFitter ├─子1 ├─子2 └─子3

含义: 内部 Vertical 自动排列子;然后 CSF 让物体 A 的外框,自动包裹住里面所有子加起来的总大小。

这个是聊天气泡、动态弹窗最经典写法,没有警告,是正确用法。

那如果我 就是想要:Horizontal 里面有一个子,大小自适应自身内容怎么办?

正确做法: 子物体不要挂 CSF,靠子身上的 LayoutElement 的 Preferred 尺寸对外上报! 父 HorizontalLayoutGroup 读取子的 Preferred,自动适配这个子的大小,这才是 Horizontal/VerticalLayoutGroup 的设计逻辑。

TMP 自带 ILayoutElement,自带 Preferred 尺寸,直接给父 Horizontal 读,不需要子加 CSF。

CSF + LayoutElement 的搭配

同一个物体:ContentSizeFitter + LayoutElement

作用: CSF 默认跟着 Preferred 走;LayoutElement 可以给它加边界限制

例子: TMP + CSF (Horizontal=Preferred) + LayoutElement

  • LayoutElement MinWidth=30,PreferredWidth=200 效果: CSF 包裹文字,但是宽度最小锁死 30;文字短的时候,框不会缩到比 30 更小。

这里是安全的,不会警告,因为这个物体外面没有 LayoutGroup 父。

4 种常用搭配速记

  1. TMP 聊天气泡:TMP + CSF Horizontal=Preferred, Vertical=Preferred (无 LayoutGroup 父)
  2. 自动包裹的容器:VerticalLayoutGroup + CSF Both Preferred (CSF 和 LayoutGroup 在同一个物体,标准写法)
  3. 横向一行,里面 TMP 文字自适应:父 HorizontalLayoutGroup,子 TMP不加 CSF,靠 TMP 原生 Preferred
  4. Grid 的子:绝对不要加 CSF,Grid 强制 CellSize,冲突爆炸

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询