27.总结
27.1 知识点

学习的主要内容

必须达到的水平

学会举一反三

一些和UI相关的知识

27.2 核心要点速览
发展脉络
| 阶段 | 要点 |
|---|---|
| Unity 早期至 4.6 之前 | 官方主推 IMGUI 写界面;要做得漂亮、好用,很多项目会用第三方 NGUI。 |
| Unity 4.6 | 官方 UGUI 落地;业界从「第三方为主」开始明显转向官方方案。 |
| Unity 5 一代 | UGUI 功能和生态更成熟,逐渐成为商业项目里的默认选择之一。 |
| Unity 2018 起 | UIElements(现多称 UI Toolkit)强化,在编辑器侧很能打;与 UGUI 长期并存,分工不同。 |
为什么要专门学 UGUI
Unity 官方大致三条线:UIElements、Unity UI(UGUI)、IMGUI。概述里用一张对标表记过典型分工(Editor 与运行时 game UI 不是同一块战场):
| 体系 | 运行时开发 UI | 运行时游戏 UI | Unity 编辑器 |
|---|---|---|---|
| UIElements | 视版本与项目而定 | 视版本与项目而定 | 主力方向之一 |
| Unity UI,UGUI | 常用 | 主力之一 | 不可用 |
| IMGUI | 多用于调试、工具向 | 不适合作为正式游戏 UI 的主力 | 常用 |
实务上:做游戏产品界面,UGUI 仍然是必须啃透的基本盘;和「只会写编辑器工具」用到的 UI 栈大概率不一样,面试里也经常被拿来对比。
学法与内容主线
- 学法:理论(组件与机制)+ 小题巩固 + 小实践串起来。
- 内容线:基础控件 → 组合控件 → 若干进阶专题 → 用 UGUI 搭完整功能。
六大基础组件与编辑器入口
- 从哪创建:在 Hierarchy 里右键 UI,子菜单里从 Text、Image、Button 到 Canvas、Event System 都是 UGUI。场景里第一次需要根节点时,Unity 往往会自动补上 Canvas 和 EventSystem。
- 编辑习惯:做布局时 Scene 切 2D 视图、多用 Rect 工具(T) 改宽高和锚点,比在 3D 透视里硬挪 Transform 省心。
标准 UGUI 场景最少要分清两套对象:Canvas 根和 EventSystem。组件怎么分挂可以按下面记:
| 挂在哪 | 组件 | 角色 |
|---|---|---|
| Canvas(及同一物体上) | Canvas | 决定渲染模式、排序等,是 UI 的「画布」 |
| Canvas Scaler | 分辨率变了 UI 怎么缩放,适配策略在这 | |
| Graphic Raycaster | 参与 UI 图形射线检测,把指针事件落到具体 Graphic 上 | |
| RectTransform | 所有可见 UI 节点都有;锚点、轴心、适配布局的核心 | |
| EventSystem | Event System | 管当前选中谁、事件往哪派发 |
| Standalone Input Module | 把鼠标键盘手柄输入翻译成 UI 事件(常见默认模块) |
Canvas画布组件
| 内容 | 详情 |
|---|---|
| Canvas 组件作用 | 用于创建和管理 UI,场景中可存在多个 Canvas 对象 |
| 渲染方式 - Screen Space - Overlay | 覆盖模式,UI 始终显示在场景内容前方,会挡住场景模型。 参数: - Pixel Perfect:是否开启无锯齿精确渲染(性能换效果) - Sort Order:多个 Overlay Canvas 叠放时数值越大越晚绘制,显示越在上层 - Target Display:目标显示设备 - Additional Shader Channels:其他着色器通道,决定着色器可读取的数据 |
| 渲染方式 - Screen Space - Camera | 摄像机模式,3D 物体可显示在 UI 之前。 参数: - RenderCamera:用于渲染 UI 的摄像机,不推荐设为主摄像机,建议创建只渲染 UI 层的摄像机并关联,设置模式为仅深度,调整深度比主摄像机高,想让模型在 UI 前可创建为 UI 子物体 - Plane Distance:UI 平面在摄像机前方的距离,类似整体 Z 轴 - Sorting Layer:所在排序层 - Order in Layer:排序层的序号 |
| 渲染方式 - World Space | 3D 模式,可将 UI 对象像 3D 物体一样处理,常用于 VR 或 AR。一般关联主摄像机,重置 UI 比例和长宽后,标准单位的 UI 图片大小和立方体一样。 参数: - Event Camera:用于处理 UI 事件的摄像机,不设置则不能正常注册 UI 事件 |
CanvasScaler画布缩放器组件
组件作用:用于对Canvas中的UI元素进行适配,以适应不同的屏幕分辨率和设备。
三种适配模式:
恒定像素模式(Constant Pixel Size):通过Scale Factor(缩放系数)和Reference Pixels Per Unit(单位参考像素)来全局缩放UI元素,单位参考像素与图片的Pixels Per Unit共同影响UI元素最终显示尺寸。缩放模式(Scale With Screen Size):最常用的模式,基于 Reference Resolution(参考分辨率)自适应。宽高比和参考不一致时靠 Screen Match Mode:Expand(扩展模式,界面尽量完整可见,可能留黑边)、Shrink(尽量铺满视口,可能裁边)、Match Width Or Height(按滑杆偏向宽或高一边匹配,UI 相对「定尺」,仍可能黑边或裁切)。恒定物理模式(Constant Physical Size):涉及DPI(每英寸点数)、Physical Unit(物理单位)、Fallback Screen DPI(备用DPI)、Default Sprite DPI(默认图片DPI)等参数,与恒定像素模式的区别在于其基于物理单位和DPI来处理UI元素的显示。3D模式(World模式):有Dynamic Pixels Per Unit(UI中动态创建位图的单位像素数)和Reference Pixels Per Unit(单位参考像素,默认一个单位为100像素)等参数,用于处理3D场景中的UI相关设置。
GraphicRaycaster 图形射线投射器
主要作用:GraphicRaycaster 用于处理 UI 元素的射线检测,确定鼠标点击或触摸事件是否发生在 UI 元素上。
参数说明
| 参数 | 说明 |
|---|---|
| Ignore Reversed Graphics | 是否忽略反转图形。若勾选,当对象旋转了 x 轴或 y 轴时,点击该对象无效;若不勾选,点击始终有效。 |
| Blocking Objects | 射线被哪些类型的碰撞器阻挡,但在覆盖渲染模式下此设置无效。可选择能阻挡射线的碰撞器类型。 |
| Blocking Mask | 射线被哪些层级的碰撞器阻挡,同样在覆盖渲染模式下无效。需配合阻塞对象使用,只有对象处于勾选的层级,并且符合阻塞对象的类型,才能阻挡射线。 |
覆盖模式特性:在覆盖模式下,由于 UI 始终显示在最前面,Blocking Objects 和 Blocking Mask 参数无效。
EventSystem 组件
| 参数 | 说明 |
|---|---|
| First Selected | 可设置游戏开始时默认选中的游戏对象,关联对象后,运行游戏该对象会被默认选中。 |
| Send Navigation Events | 决定是否允许导航事件(如移动、按下、取消等)。勾选后,可通过 wasd 或上下左右键切换选择的对象。 |
| Drag Threshold | 定义了拖拽操作的阈值,即鼠标移动多少像素后会进入拖拽状态。 |
运行时在 EventSystem 组件自带的调试视图里能看到当前选中、射线打中的对象,查「点了没反应」时很实用。
Standalone Input Module 组件
| 参数 | 说明 |
|---|---|
| Horizontal Axis | 水平轴按钮对应的热键名,该名字需对应 Input 管理器中的设置。 |
| Vertical Axis | 垂直轴按钮对应的热键名,对应 Input 管理器中的设置。 |
| Submit Button | 提交(确定)按钮对应的热键名,对应 Input 管理器中的设置。 |
| Cancel Button | 取消按钮对应的热键名,对应 Input 管理器中的设置。 |
| Input Actions Per Second | 每秒允许键盘或控制器输入的数量。 |
| Repeat Delay | 按住按键时,连发开始前等待的秒数;与 Input Actions Per Second 搭配。 |
| ForceModule Active | 决定是否强制该模块处于激活状态。一般情况下,不会对该组件的参数进行修改。 |
RectTransform矩形变换组件
| 参数 | 说明 |
|---|---|
| Pivot(轴心点) | 取值范围为 0 - 1,以左下角为原点 (0, 0),右上角为 (1, 1)。 是旋转的中心点,与锚点共同用于位置计算。 影响宽高扩大或缩小时的伸缩方向。 |
| Anchors(相对父矩形锚点) | Min 是矩形锚点范围 X 和 Y 的最小值,Max 是最大值,取值范围 0 - 1。 当 Min 和 Max 对应的 xy 值完全贴合时,锚点以点的形式存在,根据锚点位置建立坐标系,结合轴心点计算 UI 对象位置。 当 Min 和 Max 对应的 xy 值分开时,根据锚点的四条边和 UI 对象的四条边计算位置,适用于背景图或需要子对象随父对象变化而变化的情况。 |
| Pos(X, Y, Z) | 轴心点(中心点)相对锚点的位置。 |
| Width/Height | 矩形的宽高。 |
| Left/Top/Right/Bottom | 矩形边缘相对于锚点的位置,当锚点分离时出现。 |
| Rotation | 围绕轴心点旋转的角度。 |
| Scale | 缩放大小。 |
| Blueprint Mode(蓝图模式) | 启用后,编辑旋转和缩放不会影响矩形,只会影响显示内容,一般不勾选。 |
| Raw Edit Mode(原始编辑模式) | 启用后,改变轴心和锚点值不会改变矩形位置,即改变轴心位置,图片显示位置改变,但 UI 对象的 Pos 位置数值不变。 不启用时,改变轴心位置,UI 对象的 Pos 位置也会改变。 |
三大基础控件
- Image:吃
Sprite,是 UI 贴图、图标、按钮皮的主力;Image Type 管简单拉伸、九宫格、平铺、扇形/径向填充等表现。 - RawImage:吃
Texture,大图全屏底、刻意不进图集的资源、运行时整张替换(含远端下载)都常见用它;UV Rect 在归一化坐标里裁一块区域显示。 - Text(Legacy):字符串显示 + Rich Text 标签;描边、阴影要另挂 Outline、Shadow 组件。三个都是 Graphic 后代,都有 Raycast Target,叠层时要注意谁挡住了点击。
Image图片控件
Image 图片组件参数
| 参数 | 说明 |
|---|---|
| Source Image(源图形) | 图片来源,图片类型必须是“精灵”类型。 |
| Color(颜色) | 图像的颜色,会在原图基础上叠加。 |
| Material(材质) | 图像的材质,一般使用 UI 的默认材质,不做修改。 |
| Raycast Target(射线目标) | 是否作为射线检测的目标,不勾选则不会响应射线检测,可穿透当前控件点击到后面的控件。 |
| Maskable | 是否能被遮罩,后续结合遮罩相关知识点讲解。 |
| Image Type(图片类型) | Simple(普通模式):均匀缩放整个图片。 Sliced(切片模式):9 宫格拉伸,只拉伸中央十字区域,需打开精灵编辑开启设置九宫格;Pixels Per Unit Multiplier 一般不修改;Fill Center 不勾选图片会中间空心。 Tiled(平铺模式):重复平铺中央部分。 Filled(填充模式):可用于做血条、cd 进度条等,有 Fill Method(填充方式)、Fill Origin(填充原点)、Fill Amount(填充量)、Clockwise(顺时针方向)等参数。 |
| Use Sprite Mesh(使用精灵网格) | 勾选后 Unity 会帮我们生成图片网格。 |
| Preserve Aspect(保持长宽比) | 缩放时保持图片宽高比,避免被拉变形。 |
| Set Native Size(设置原生大小) | 按当前 Sprite 的原始像素尺寸同步 RectTransform 宽高(与「铺满视口」无关)。 |
Image 图片代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 Image 组件 | Image image = this.GetComponent<Image>(); |
获取当前脚本所附加的 GameObject 上的 Image 组件。 |
| 设置显示图像 | image.sprite = Resources.Load<Sprite>("ui_TY_fanhui_01"); |
从资源文件夹中加载名为 “ui_TY_fanhui_01” 的 Sprite,并将其设置为 Image 的显示图像。 |
| 设置宽高 | (transform as RectTransform).sizeDelta = new Vector2(200, 200); |
将当前 GameObject 的 Transform 转换为 RectTransform,然后修改其尺寸为宽度 200、高度 200。 |
| 设置是否进行射线检测 | image.raycastTarget = false; |
禁用该 Image 组件的射线检测,使其不响应用户的点击事件。 |
| 设置颜色 | image.color = Color.red; |
将该 Image 组件的颜色设置为红色。 |
Text
Text 文本组件参数
| 参数 | 说明 |
|---|---|
| Text(文本) | 文本显示内容。 |
| Font(字体) | 文本所使用的字体。 |
| FontStyle(字体样式) | 包括 Normal(普通)、Bold(加粗)、Italic(斜体)、Bold And Italic(加粗 + 斜体)。 |
| Font Size(字体大小) | 文本字体的大小。 |
| Line Spacing(行间距) | 行之间的垂直间距。 |
| Rich Text(富文本) | 是否开启富文本功能。 |
| Raycast Target | 与 Image 相同,来自 Graphic;纯展示、不挡下面按钮时应关掉。 |
| Alignment(对齐方式) | 文本的对齐方式。 |
| Align By Geometry(几何对齐) | 使用字形集合形状范围进行水平对齐,而非字形指标,一般不勾选。 |
| Horizontal Overflow(水平溢出) | 处理文本太宽无法放入矩形范围的方式,有 Wrap(包裹模式,自动换行)和 Overflow(溢出模式,可溢出矩形框)。 |
| Vertical Overflow(垂直溢出) | 处理文本太高无法放入矩形范围的方式,有 Truncate(截断模式,超出部分裁剪)和 Overflow(溢出模式,可溢出矩形框)。 |
| Best Fit(最佳适应) | 忽略字体大小,自动调整使内容完全显示在矩形框中,可设置 MinSize(最小字体大小)和 MaxSize(最大字体大小)。 |
富文本使用
需开启富文本选项才能生效,示例如下:
- 加粗:
<b>文本内容</b> - 斜体:
<i>文本内容</i> - 大小:
<size=50>文本内容</size> - 颜色:
<color=#ff0000ff>文本内容</color>或<color=red>文本内容</color>
边缘线和阴影
若要添加边缘线和阴影效果,需自行添加对应的组件,如 Outline(边缘线组件)和 Shadow(阴影组件)。
Text 文本代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 Text 组件 | Text text = this.GetComponent<Text>(); |
获取当前脚本所附加的 GameObject 上的 Text 组件。 |
| 设置文本显示内容 | text.text = "哈哈哈哈哈"; |
通过 text.text 变量设置文本显示内容。 |
RawImage
RawImage 原始图像组件参数
| 参数 | 说明 |
|---|---|
| Texture(图像纹理) | 可以拖拽任何类型的图进行关联。 |
| UV Rect(UV 矩形) | 表示图像在 UI 矩形内的偏移和大小。位置偏移 X 和 Y 取值范围是 0 - 1,大小偏移 W 和 H 取值范围也是 0 - 1。改变这些值,图像边缘会进行拉伸来填充 UV 矩形周围的空间,一般情况下不会改变此参数。 |
RawImage 原始图像代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 RawImage 组件 | RawImage rawImage = this.GetComponent<RawImage>(); |
获取当前脚本所附加的 GameObject 上的 RawImage 组件。 |
| 设置纹理 | rawImage.texture = Resources.Load<Texture>("ui_TY_lvseshuzi_08"); |
从资源文件夹中加载名为 “ui_TY_lvseshuzi_08” 的 Texture,并将其设置为 RawImage 组件的显示纹理。 |
| 设置 UV 矩形 | rawImage.uvRect = new Rect(0, 0, 1, 1); |
设置 RawImage 组件的纹理坐标矩形,创建一个左下角坐标为 (0, 0),宽度和高度都为 1 的 Rect 对象。 |
组合控件共通
- Selectable 一族(Button、Toggle、Slider 等):多数带 Interactable、Transition(None / ColorTint / Sprite Swap / Animation)、Navigation。禁用交互时勾掉 Interactable 即可统一灰显、不收输入。
- 事件怎么接:点按一次 — Button.onClick;bool 状态 — Toggle.onValueChanged;连续数值 — Slider / **Scrollbar.onValueChanged(float)**;文本 — InputField.onValueChanged 与 onEndEdit;下拉索引 — **Dropdown.onValueChanged(int)**。Inspector 多用 Dynamic 绑定才能把运行时参数传进方法。
Button按钮控件
- 默认结构:父物体挂 Button + Image(可点底图),子物体可挂 Text 做字。改外观通常直接改这张 Image 的 Sprite / Color。
- OnClick:在按钮区域内按下并抬起完成一次有效点击(中间滑出按钮区域会取消)。
| 要点 | 说明 |
|---|---|
| Transition | Color Tint / Sprite Swap / Animation 或用 None 省状态;Sprite Swap 下是 Selected Sprite 等图槽,不是颜色槽。 |
| Navigation | 配合 EventSystem 做方向键、Tab 切焦点;Explicit 可手工指定相邻控件。 |
| 代码 | button.onClick.AddListener(...),成对 RemoveListener,清表用 RemoveAllListeners。 |
Toggle
Toggle 开关组件参数
| 参数 | 说明 |
|---|---|
| Interactable | 决定是否接受输入。 |
| Transition | 响应用户输入的过渡效果。 |
| Navigation | 导航模式,设置 UI 元素在播放模式中控制器导航的方式。 |
| IsOn | 表示当前是否处于打开状态。 |
| Toggle Transition | 开关值变化时的过渡方式,有 None(无过渡,直接显示隐藏)和 Fade(淡入淡出)两种。 |
| Graphic | 用于表示选中状态的图片,默认关联创建 Toggle 时自动生成的勾形状选中图对象。 |
| Group | 关联的 ToggleGroup 单选框分组组件。创建一个空物体添加 ToggleGroup 组件作为管理组对象,将需管理的 Toggle 放在其下,并将每个 Toggle 的 Group 关联该 ToggleGroup 对象可实现单选框功能。Allow Switch Off 属性决定是否允许不选中任何一个单选框。 |
| OnValueChanged | 开关状态变化时执行的函数列表。 |
Toggle 开关代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 Toggle 组件 | Toggle toggle = this.GetComponent<Toggle>(); |
获取当前脚本所附加 GameObject 上的 Toggle 组件。 |
| 设置 Toggle 状态 | toggle.isOn = true; |
将 Toggle 状态设置为打开。 |
| 获取 ToggleGroup 组件 | ToggleGroup toggleGroup = this.GetComponent<ToggleGroup>(); |
获取当前脚本所附加 GameObject 上的 ToggleGroup 组件。 |
| 设置 ToggleGroup 属性 | toggleGroup.allowSwitchOff = false; |
禁止取消选中所有 Toggle。 |
| 获取 ToggleGroup 中选中的 Toggle | foreach (Toggle item in toggleGroup.ActiveToggles()) { print(item.name + " " + item.isOn); } |
遍历 ToggleGroup 中处于选中状态的 Toggle 并打印其名称和状态。 |
Toggle 监听事件的两种方式
拖脚本添加事件监听
在 Toggle 组件的 On Value Changed 列表里点加号,拖入对象并选带 bool 参数的公共方法,可挂多个回调。示例方法如下:
public void ChangeValue(bool isOn)
{
print("状态改变" + isOn);
}
代码添加事件监听
使用 toggle.onValueChanged.AddListener 添加值改变事件监听。示例代码如下:
private void ChangeValue2(bool v)
{
print("代码监听 状态改变" + v);
}
// 监听 toggle 的值改变事件,当值改变时调用 ChangeValue2 方法
toggle.onValueChanged.AddListener(ChangeValue2);
// 使用 lambda 表达式定义一个匿名方法并监听 toggle 的值改变事件
toggle.onValueChanged.AddListener((b) =>
{
print("代码监听lambda表达式 状态改变" + b);
});
InputField
InputField文本输入组件参数
| 参数名称 | 描述 |
|---|---|
| Interactable | 是否接受输入 |
| Transition | 响应用户输入的过渡效果 |
| Navigation | 导航模式,设置UI元素在播放模式中控制器导航的方式 |
| TextComponent | 用于关联显示输入内容的文本组件 |
| Text | 输入框的起始默认值,也是当前文本输入的内容 |
| Character Limit | 可以输入字符长度的最大值 |
| Content Type | 输入的字符类型限制,包括Standard(标准模式)、Autocorrected(自动更正模式)、Integer Number(整数模式)、Decimal Number(十进制数模式)、Alphanumeric(字母数字模式)、Name(名字模式)、Email Address(邮箱地址模式)、Password(密码模式)、Pin(PIN 码模式)、Custom(自定义模式)等 |
| Line Type | 定义文本格式,有Single Line(单行显示)、Multi Line Submit(多行提交)、Multi Line NewLine(多行换行)三种模式 |
| Placeholder | 关联用于显示初始内容文本控件 |
| Caret Blink Rate | 光标闪烁速率 |
| Caret Width | 光标宽度 |
| Custom Caret Color | 自定义光标颜色 |
| Selection Color | 批量选中的背景颜色 |
| Hide Mobile Input | 隐藏移动设备屏幕上键盘,仅适用于iOS |
| Read Only | 设置为只读,用户无法修改,输入无作用 |
| OnValueChanged | 内容改变时执行的函数列表 |
| OnEndEdit | 结束输入时执行的函数列表 |
InputField监听事件的两种方式
拖脚本监听事件
函数需有一个string类型的参数,选择动态的函数。对文本输入框的任何输入都会调用值改变时的事件,焦点不在文本输入框上就会调用结束编辑时的事件。示例代码如下:
public void ChangeInput(string str)
{
print("改变的输入内容" + str);
}
public void EndInput(string str)
{
print("结束输入时内容" + str);
}
代码添加监听事件
通过InputField.onValueChanged.AddListener添加值改变事件监听,InputField.onEndEdit.AddListener添加结束编辑事件监听。示例代码如下:
// 给inputField的onValueChanged事件添加监听器,当输入框文本内容改变时触发
inputField.onValueChanged.AddListener((str) =>
{
print("代码监听 改变" + str);
});
// 给inputField的onEndEdit事件添加监听器,当输入框结束编辑时触发
inputField.onEndEdit.AddListener((str) =>
{
print("代码监听 结束输入" + str);
});
Slider
Slider 滑动条组件参数
| 参数名称 | 描述 |
|---|---|
| FillRect | 关联的用于填充的进度条图形对象 |
| Handle Rect | 关联的用于滑动的滑动块图形对象 |
| Direction | 滑动条值增加的方向,包含: - Left To Right:从左到右 - Right To Left:从右到左 - Bottom To Top:从下到上 - Top To Bottom:从上到下 |
| Min Value 和 Max Value | 最小值和最大值,滑动滚动条时值在最小到最大之间变化(左右、上下极值) |
| Whole Numbers | 是否约束为整数值变化 |
| Value | 当前滑动条代表的数值 |
| OnValueChanged | 滑动条值改变时执行的函数列表 |
Slider 监听事件的两种方式
拖脚本监听事件
关联的函数要有一个 float 类型的参数,要选择动态的函数。若选择静态,值改变时会只打印右边输入框的值。示例函数如下:
public void ChangeValue(float v)
{
print(v);
}
代码添加监听事件
slider.onValueChanged.AddListener(ChangeValue);
slider.onValueChanged.AddListener((v) => { print("代码添加的监听" + v); });
ScrollBar
ScrollBar 滚动条组件参数
| 参数名称 | 描述 |
|---|---|
| Handle Rect | 关联滚动块图形对象。 |
| Direction | 滑动条值增加的方向,包括: Left To Right:从左到右 Right To Left:从右到左 Bottom To Top:从下到上 Top To Bottom:从上到下 |
| Value | 滚动条初始位置值,范围是 0 到 1。 |
| Size | 滚动块在条中的比例大小,范围是 0 到 1,为 1 时填满,代表不能拖动。 |
| Number Of Steps | 允许可以滚动的次数(不同滚动位置的数量),即可以一格一格变化时分成的格数。 |
| OnValueChanged | 滚动条值改变时执行的函数列表。 |
ScrollBar 滚动条控件代码控制
- 通过 GetComponent
() 得到 Scrollbar 组件,如 Scrollbar scrollbar = this.GetComponent<Scrollbar>();。 - 使用 Scrollbar.value 获取滚动条当前值,例如
print(scrollbar.value);。 - 使用 Scrollbar.size 获取滚动条大小,例如
print(scrollbar.size);。
ScrollBar 监听事件的两种方式
拖脚本监听事件
函数需要一个 float 参数,代表滚动条的值。示例代码如下:
public void ChangeValue(float v)
{
print(v);
}
代码添加监听事件
通过 scrollbar.onValueChanged.AddListener 添加滑动条值变化的监听。示例代码如下:
// 注册监听滑动条值变化的事件,当滑动条的值发生变化时,执行下面的函数
scrollbar.onValueChanged.AddListener((v) => {
print("代码监听的函数" + v);
});
ScrollView滚动视图控件
ScrollRect 滚动视图组件参数
| 参数名称 | 描述 |
|---|---|
| Content | 控制滚动视图显示内容的父对象,其尺寸决定滚动视图的拖动范围,默认关联 Viewport 的子对象 Content |
| Horizontal | 启用水平滚动 |
| Vertical | 启用垂直滚动 |
| Movement Type | 滚动视图元素的运动类型,控制拖动时的反馈效果: - Unrestricted:不受限制,随意拖动 - Elastic:回弹效果,滚出边缘后会弹回边界,Elasticity 为回弹系数,值越大回弹越慢 - Clamped:夹紧效果,始终限制在范围内,无回弹效果 |
| Inertia | 移动惯性,开启后松开鼠标有一定移动惯性 |
| Deceleration Rate | 减速率,范围 0 - 1,0 表示无惯性,1 表示不会停止 |
| Scroll Sensitivity | 滚轮和触摸板的滚动事件敏感性,增大值可加快滚轮滚动速度 |
| Viewport | 关联滚动视图内容视口对象,决定可视范围 |
| Horizontal Scrollbar | 关联水平滚动条 |
| Visibility | 设置滚动条的可视性模式: - Permanent:一直显示滚动条 - Auto Hide:自动隐藏滚动条,不自动扩展视口范围 - Auto Hide And Expand Viewport:自动隐藏滚动条,并自动扩展内容 Viewport 视口范围 |
| Spacing | 滚动条和视口之间的间隔空间,控制间隙大小 |
| OnValueChanged | 滚动视图位置改变时执行的函数列表 |
删掉自带 Scrollbar 时,要在 ScrollRect 上把 Horizontal / Vertical Scrollbar 引用清空,并顺手把 Viewport、底图 Image 拉满,否则容易沿用「给滚动条留缝」的旧布局,留下空白或古怪间距。
ScrollRect 滚动视图代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 ScrollRect 组件 | ScrollRect scrollRect = this.GetComponent<ScrollRect>(); |
获取当前游戏对象上的 ScrollRect 组件 |
| 改变内容对象大小 | scrollRect.content.sizeDelta = new Vector2(1000, 1000); |
改变内容的大小,决定具体可拖动范围 |
| 设置滑动面板归一化位置 | scrollRect.normalizedPosition = new Vector2(0, 1f); |
重置 content 位置到左上,x 表示水平方向归一化值(0 - 1),y 表示垂直方向归一化值(0 - 1) |
ScrollView 监听事件的两种方式
拖脚本监听事件
public void ChangeValue(Vector2 v)
{
print(v);
}
代码添加监听事件
scrollRect.onValueChanged.AddListener((vec) =>
{
print(vec);
});
Dropdown下拉列表控件
DropDown 下拉列表组件参数
| 参数名称 | 描述 |
|---|---|
| Template | 关联下拉列表对象 |
| Caption Text | 关联显示当前选择内容的文本组件 |
| Caption Image | 关联显示当前选择内容的图片组件,可能需手动创建 Image |
| Item Text | 关联下拉列表选项用的文本控件 |
| Item Image | 关联下拉列表选项用的图片控件,可能需手动创建 Image |
| Value | 当前所选选项的索引值 |
| Alpha Fade Speed | 下拉列表窗口淡入淡出的速度,越小显示越快 |
| Options | 存在的选项列表 |
| OnValueChanged | 下拉列表选项改变时执行的函数列表 |
DropDown 下拉列表代码控制
| 操作 | 代码示例 | 说明 |
|---|---|---|
| 获取 DropDown 组件 | Dropdown dropdown = GetComponent<Dropdown>(); |
获取当前脚本所附加游戏对象上的 DropDown 组件 |
| 获取当前选中项索引 | print(dropdown.value); |
打印下拉菜单当前选中项的索引 |
| 获取当前选中项文本内容 | print(dropdown.options[dropdown.value].text); |
打印下拉菜单当前选中项的文本内容 |
| 添加新选项 | dropdown.options.Add(new Dropdown.OptionData("123123123")); |
在下拉菜单的选项列表末尾添加一个新选项 |
DropDown 监听事件的两种方式
拖脚本监听事件
需要一个 Int 类型的参数,代表下拉列表的索引值。示例代码如下:
public void ChangeValue(int value)
{
print(value);
}
代码添加监听事件
dropdown.onValueChanged.AddListener((index) =>
{
print(index);
});
图集
- 相对 NGUI 的习惯:NGUI 往往一上来就定图集;UGUI 可以先把界面搭顺,再集中打图集、收引用。
- 为什么要打:多张小图若各自成材质/批次,容易把 DrawCall(DC) 顶高。DC 是 CPU 向 GPU 排队提交绘制 的密集程度指标,太高会占 CPU、表现为卡顿。把小图 打进少量大图,同屏 UI 更容易用 更少批次画完;口语里说「n 张碎图合成 1 张大图减 DC」是教学简化,实际批次还与 材质、Canvas 是否拆分等有关,但图集仍是 UI 性能课的常规手段。
在 Edit → Project Settings → Editor 中配置 Sprite Packer(条目名以当前 Unity 版本为准),模式可按下表理解:
| 设置模式 | 描述 | 是否在编辑模式下打包 | 是否在构建时打包 | 特殊选项 |
|---|---|---|---|---|
| Disabled | 不打图集;非 2D 工程常见默认 | 否 | 否 | 无 |
| Enabled For Builds(Legacy Sprite Packer) | 仅构建时打 | 否 | 是 | Padding Power:缝大小按 2^n 像素量级 |
| Always Enabled(Legacy Sprite Packer) | 构建时打;编辑器里运行前也会打 | 是(运行前) | 是 | 同上 |
| Enabled For Build | 仅构建时打(非 Legacy 文案) | 否 | 是 | 无 |
| Always Enabled | 构建时打;编辑模式运行前也会打 | 是(运行前) | 是 | 无 |
- 打包勾选:原文建议 UGUI 图集勾选项里 关掉「允许旋转」「紧密包装」,减少算法排布上的意外。
代码加载(using UnityEngine.U2D):
SpriteAtlas spriteAtlas = Resources.Load<SpriteAtlas>("MyAtlas");
Sprite s = spriteAtlas.GetSprite("bk"); // 与图集中子 Sprite 名称一致,再赋给 Image.sprite 等
进阶:事件、坐标与裁切
- 事件扩展:命名空间
UnityEngine.EventSystems。Button / Toggle 自带 UnityEvent 不够用时(长按、拖拽、双击、让纯 Image 吃指针),用IPointerX/IDragX等接口在脚本里实现回调;OnPointerEnter / Exit 在纯触摸环境往往弱于键鼠。 - EventTrigger:把多路事件挂到
triggers列表;每条EventTrigger.Entry= **EventTriggerType+callback**,与手写多接口等价,Inspector 里拖BaseEventData方法常用as PointerEventData取坐标。 - 屏幕 → UI 本地:
RectTransformUtility.ScreenPointToLocalPointInRectangle,父RectTransform、屏幕点、负责渲染的 Camera、out本地坐标;拖拽里相机常用eventData.pressEventCamera或enterEventCamera,与当前 Canvas 模式一致。 - Mask:父级 Mask 按自身图 Alpha 裁子树;被子 Graphic 需 Maskable。ScrollView 的 Viewport 常带遮罩裁滚动内容。
- 3D / 粒子在 UI 前:非 Overlay 可掰 Z;或 专用相机 → RenderTexture → RawImage(与 Canvas 模式无关);粒子可用 Renderer 排序层压过 UI。
- 异形点击:子 Image 拼可点区域(自下而上叠射线);或
alphaHitTestMinimumThreshold,Sprite 通常要开 Read/Write Enabled。 - 自动布局:LayoutElement(Min / Preferred / Flexible)→ Horizontal & Vertical Layout Group、Grid Layout Group、Content Size Fitter、Aspect Ratio Fitter。
- CanvasGroup:一把控制子树 Alpha、Interactable、Blocks Raycasts;Ignore Parent Groups 可脱开上层 CanvasGroup 的叠加。
UI事件监听接口
UGUI 事件接口列表
常用事件接口
| 接口名 | 接口函数名 | 解释说明 |
|---|---|---|
| IPointerEnterHandler | OnPointerEnter | 鼠标指针进入对象时调用 |
| IPointerExitHandler | OnPointerExit | 鼠标指针退出对象时调用 |
| IPointerDownHandler | OnPointerDown | 在对象上按下鼠标指针时调用 |
| IPointerUpHandler | OnPointerUp | 松开鼠标指针时(在指针点击的对象上)调用 |
| IPointerClickHandler | OnPointerClick | 在同一对象上按下再松开鼠标指针时调用 |
| IBeginDragHandler | OnBeginDrag | 即将开始拖拽时在拖拽对象上调用 |
| IDragHandler | OnDrag | 发生拖拽时在拖拽对象上调用 |
| IEndDragHandler | OnEndDrag | 拖拽完成时在拖拽对象上调用 |
不常用事件接口
| 接口名 | 接口函数名 | 解释说明 |
|---|---|---|
| IInitializePotentialDragHandler | OnInitializePotentialDrag | 找到拖动目标时调用,可用于初始化值 |
| IDropHandler | OnDrop | 在拖动目标对象上调用 |
| IScrollHandler | OnScroll | 鼠标滚轮滚动时调用 |
| IUpdateSelectedHandler | OnUpdateSelected | 对象处于被选中状态时,每帧在选定对象上调用 |
| ISelectHandler | OnSelect | 对象成为选定对象时调用 |
| IDeselectHandler | OnDeselect | 取消选择选定对象时调用 |
导航相关接口
| 接口名 | 接口函数名 | 解释说明 |
|---|---|---|
| IMoveHandler | OnMove | 发生移动事件(上、下、左、右等)时调用 |
| ISubmitHandler | OnSubmit | 按下 Submit 按钮时调用 |
| ICancelHandler | OnCancel | 按下 Cancel 按钮时调用 |
PointerEventData 指针目标数据类参数详解
PointerEventData 类继承自 BaseEventData 类,是 UGUI 事件系统中存储用户输入设备交互信息的重要参数,包含以下关键属性:
| 属性名 | 描述 |
|---|---|
| pointerId | 代表用户操作中不同按键的唯一标识,用于识别触发事件的按键 |
| position | 当前指针在屏幕坐标系中的实时位置,拖拽时持续更新 |
| pressPosition | 指针按下那一刻在屏幕上的初始位置 |
| delta | 从上一次事件到当前事件期间,指针在屏幕上的位移变化量 |
| clickCount | 连续点击的次数,用于区分单击和连击行为 |
| clickTime | 最后一次点击发生的时间戳,用于根据点击间隔执行不同逻辑 |
| pressEventCamera | 最后一次触发按下事件时所关联的摄像机实例 |
| enterEventCamera | 最后一次触发进入事件时所关联的摄像机实例 |
UI事件监听接口(EventTrigger)
使用事件触发器的方法
(1)拖曳脚本进行关联事件
关联的函数需要有一个 BaseEventData 参数。以下是示例代码:
public void TestPointerEnter(BaseEventData data)
{
// 可以转换成子类 PointerEventData
PointerEventData eventData = data as PointerEventData;
print("鼠标进入 " + eventData.position);
}
通常的操作是将面板对象拖拽进来,然后选择面板脚本上的函数进行关联。
(2)代码添加
// 声明一个希望监听的事件对象 EventTrigger.Entry
// EventTrigger.Entry包含一个事件的类型ID eventID
// 和一个事件回调 callback
EventTrigger.Entry entry = new EventTrigger.Entry();
// 声明事件的类型为 PointerUp 指针抬起事件
entry.eventID = EventTriggerType.PointerUp;
// PointerUp 回调示例
entry.callback.AddListener((data) =>
{
print("抬起");
});
// 把声明好的事件对象加入到 EventTrigger 当中叫triggers的entry列表中
eventTrigger.triggers.Add(entry);
屏幕坐标转UI相对坐标
RectTransformUtility类:是 RectTransform 的辅助类,主要用于坐标转换等操作。当前重要的函数是将屏幕空间上的点转换成 UI 本地坐标下的点。
坐标转换方法:RectTransformUtility.ScreenPointToLocalPointInRectangle 方法可将屏幕坐标点转换为父对象的本地坐标系中的点。该方法有四个参数:相对父对象、屏幕点坐标、摄像机、最终得到的点坐标。一般配合拖拽事件使用。
示例代码:
public class Lesson21_UGUI进阶_屏幕坐标转UI相对坐标 : MonoBehaviour, IDragHandler
{
public RectTransform parent; // 父对象
public void OnDrag(PointerEventData eventData)
{
Vector2 nowPos; // 当前位置
// 执行完这个函数后,会把屏幕坐标转换成 UI 本地坐标系下的值赋值给 nowPos
RectTransformUtility.ScreenPointToLocalPointInRectangle(
parent, // 相对父对象
eventData.position, // 屏幕点坐标
eventData.enterEventCamera, // 摄像机
out nowPos); // 最终得到的点坐标
this.transform.localPosition = nowPos; // 将当前对象的本地位置设置为转换后的坐标
}
}
Mask遮罩
遮罩定义:遮罩是一种在不改变图片的情况下,让图片在游戏中只显示其中一部分的组件。ScrollView 滚动视图中的 ViewPort 就包含遮罩组件,使得滚动视图中只有在可见范围内才能看到组件。
遮罩使用方法:关键组件是 Mask 组件,在父对象上添加 Mask 组件即可遮罩其子对象。需要注意的是,想要被遮罩的 Image 需要勾选 Maskable;只要父对象添加了 Mask 组件,所有的 UI 子对象都会被遮罩;遮罩父对象图片不透明的地方显示,透明的地方被遮罩。
Mask遮罩模型、粒子特效显示在UI之前
- 直接用摄像机渲染 3D 物体:当 Canvas 的渲染模式不是覆盖模式(摄像机模式和世界(3D)模式)时,只要模型的 Z 轴在 UI 元素之前,模型就可以显示在 UI 之前。建议使用专门的摄像机渲染 UI 相关内容,UI 面板上的 3D 物体也用 UI 摄像机进行渲染。实现方法是设置一个专门渲染 UI 层的摄像机,让主摄像机不渲染 UI 层,UI 摄像机关联 Canvas,并将 Canvas 的渲染模式设置成摄像机模式,然后在 Canvas 上创建 Cube,调整缩放尺寸,层级设置为 UI 层,通过调整 Z 轴控制其显示位置。
- 将 3D 物体渲染在图片上,通过图片显示:专门使用一个摄像机渲染 3D 模型,将其渲染内容输出到 Render Texture 上,再将渲染的图显示在 UI 上。这种方式不受 Canvas 渲染模式的限制。实现步骤为创建一个模型层,创建一个专门渲染模型层的摄像机并改成纯色模式,创建一个立方体并设置为模型层,创建 RenderTexture 渲染器纹理并关联模型摄像机,在 Canvas 下创建 RawImage 并关联 RenderTexture 渲染器纹理。
- 粒子特效显示在 UI 之前:粒子特效的显示和 3D 物体类似。在摄像机模式下,可以在粒子组件的 Renderer 相关参数中改变排序层,让粒子特效始终显示在 UI 之前,不受 Z 轴影响。
异形按钮
异形按钮定义:形状不是传统矩形的按钮,例如只有独角兽区域能够被点击响应的按钮。
实现准确点击的方法:
- 添加子对象的形式:按钮根据图片矩形范围判断点击响应,范围判断自下而上,有子对象图片时,子对象图片范围也算可点击范围。可以用多个透明图拼凑不规则图形作为按钮子对象进行射线检测。
- 代码改变图片的透明度响应阈值:
Image.alphaHitTestMinimumThreshold,低于阈值的像素不参与射线命中;Sprite 资源通常需在 Import Settings 中开启 Read/Write Enabled 才会按像素 Alpha 做检测。
自动布局组件
布局元素的布局属性
要参与自动布局,布局元素必须包含布局属性,主要有以下 6 条:
| 属性名称 | 描述 |
|---|---|
| Minimum width | 该布局元素应具有的最小宽度 |
| Minimum height | 该布局元素应具有的最小高度 |
| Preferred width | 在分配额外可用宽度之前,此布局元素应具有的宽度 |
| Preferred height | 在分配额外可用高度之前,此布局元素应具有的高度 |
| Flexible width | 此布局元素应相对于其同级而填充的额外可用宽度的相对量 |
| Flexible height | 此布局元素应相对于其同级而填充的额外可用高度的相对量 |
布局时,布局元素大小设置遵循以下规则:
- 首先分配最小大小(Minimum width 和 Minimum height)。
- 若父容器有足够可用空间,则分配 Preferred width 和 Preferred height。
- 若上述分配完成后仍有额外空间,则分配 Flexible width 和 Flexible height。
一般情况下,布局元素的这些属性值为 0,但特定 UI 组件(如 Image 和 Text)依附对象的布局属性可能会改变。通常无需手动修改这些属性,若有需要,可手动添加 LayoutElement 组件进行修改。
常见自动布局组件
HorizontalVerticalLayoutGroup 水平垂直布局组件
即 Inspector 中的 Horizontal Layout Group 与 Vertical Layout Group,将子对象横排或纵排;组件挂在父物体,子物体被布局。其参数如下:
| 参数名称 | 描述 |
|---|---|
| Padding | 左右上下边缘的偏移位置 |
| Spacing | 子对象之间的间距 |
| ChildAlignment | 九宫格对齐方式 |
| Control Child Size | 是否控制子对象的宽高 |
| Use Child Scale | 在设置子对象大小和布局时,是否考虑子对象的缩放 |
| Child Force Expand | 是否强制子对象扩展以填充额外可用空间 |
LayoutElement 布局元素组件
可给子对象添加该组件,例如设置布局属性最小宽和最小高为 100,即便父对象很小,子对象最小也会保持宽高 100。
GridLayoutGroup 网格布局组件
可将子对象当成格子,并设置它们的大小和位置,一般在滚动容器添加到 content 上,和 ContentSizeFitter 内容大小适配器一起使用。其参数如下:
| 参数名称 | 描述 |
|---|---|
| Padding | 左右上下边缘的偏移位置 |
| Cell Size | 每个格子的大小 |
| Spacing | 格子之间的间隔 |
| Start Corner | 第一个元素所在的位置(四个角) |
| Start Axis | 沿着哪个轴放置元素,Horizontal 水平放置并换行,Vertical 竖直放置并换列 |
| Child Alignment | 格子的对齐方式(九宫格) |
| Constraint | 行列约束,有 Flexible(灵活模式,根据容器大小自动适应)、Fixed Column Count(固定列数)、Fixed Row Count(固定行数)三种模式 |
ContentSizeFitter 内容大小适配器
可自动调整 RectTransform 的宽度和高度,使组件自动设置大小,常用于 Text 组件,或与其他布局组件一起使用。其参数如下:
| 参数名称 | 描述 |
|---|---|
| Horizontal Fit | 控制宽度的方式 |
| Vertical Fit | 控制高度的方式 |
可选参数包括:
- Unconstrained:不根据布局元素伸展宽度或高度。
- Min Size:根据布局元素的最小宽度或高度伸展。
- Preferred Size:根据布局元素的首选宽度或高度伸展宽度。
若滚动视图中的元素动态添加,滚动视图不会自动改变大小,可给滚动视图添加自动布局组件和内容大小适配器组件,使其动态添加时自动更改宽高。
AspectRatioFitter 宽高比适配器
可让布局元素按一定比例调整自身大小,并在父对象内部根据父对象大小进行适配。其参数如下:
| 参数名称 | 描述 |
|---|---|
| Aspect Mode | 适配模式,用于调整矩形大小以实现宽高比 |
| Aspect Ratio | 宽度除以高度的比值,即宽高比 |
Aspect Mode 的可选值及含义:
- None:不对矩形进行宽高比适配。
- Width Controls Height:根据宽度自动调整高度。
- Height Controls Width:根据高度自动调整宽度。
- Fit In Parent:自动调整宽度、高度、位置和锚点,使矩形适应父项的矩形,同时保持宽高比,可能会出现“黑边”。
- Envelope Parent:自动调整宽度、高度、位置和锚点,使矩形覆盖父项的整个区域,同时保持宽高比,可能会出现“裁剪”。
CanvasGroup画布组
| 参数名称 | 描述 |
|---|---|
| Alpha | 用于整体控制面板的透明度,通过调整该值可实现面板的淡入淡出效果 |
| Interactable | 控制面板整体的启用和禁用状态。设置为 true 时,面板及其子对象可与用户交互;设置为 false 时,面板及其子对象无法与用户交互 |
| Blocks Raycasts | 用于设置面板是否阻挡射线检测。设置为 true 时,面板会阻挡射线;设置为 false 时,射线可穿过面板 |
| Ignore Parent Groups | 勾选后,该物体子树在计算 Alpha / Interactable / Blocks Raycasts 时不再吃父级 CanvasGroup 的成组效果;用于嵌套面板要单独淡入淡出或与父层点击穿透策略解耦时 |
27.3 面试题精选
基础题
1. 六大基础组件挂在哪两个物体上
题目
UGUI 常说的「六大基础组件」分别是什么?一般各自挂在场景的哪两个节点上?
深入解析
- Canvas 物体上四个:Canvas、Canvas Scaler、Graphic Raycaster,再加和 Transform 一体的 RectTransform(所有 UI 节点都有)。
- EventSystem 物体上两个:Event System、Standalone Input Module。输入经 EventSystem 分发,GraphicRaycaster 侧才把点按到具体 Image、Button 上。
- 记法:一半管「画出来和怎么适配、怎么射线检测」,一半管「谁收到了输入」。
答题示例
Canvas 上有 Canvas、Canvas Scaler、Graphic Raycaster,再加 RectTransform。
EventSystem 上有 Event System 和 Standalone Input Module,负责点击和导航事件。
参考文章
- 2.UGUI基础-六大基础组件-概述
2. Image 和 RawImage 资源类型差在哪
题目
UGUI 里 Image 和 RawImage 分别接什么类型的资源?各举一个更合适的用法。
深入解析
- Image 的 Source Image 必须是
Sprite,和图集、九宫格切片、Image Type 那一套深度绑定,适合做图标、按钮、血条底图等高频 UI 元素。 - RawImage 的 Texture 可以是任意
Texture(含Texture2D等),不强求先进 Atlas;全屏背景、刻意不打图集的大图、网络拉下来的整张纹理更省心。 - 答到「Sprite vs Texture」「谁更贴 UI 工作流、谁更贴纯贴图/大图」就及格。
答题示例
Image 用 Sprite,做 UI 切片、按钮图;RawImage 用 Texture,大图底图或不进图集的资源。
要和 Image Type、图集打配合就用 Image;只要整张往屏上糊或经常换一张 Texture 就用 RawImage。
参考文章
- 8.UGUI基础-三大基础控件-Image图片控件
- 10.UGUI基础-三大基础控件-RawImage原始图像控件
3. Button 的 onClick 什么时候触发、怎么接代码
题目
UGUI Button 的 On Click 大概在什么时机触发?Inspector 挂方法和 onClick.AddListener 各要注意什么?
深入解析
- 时机:指针在按钮可交互区域内完成一次按下再抬起,且未因移出区域等原因取消,UnityEvent 才派发;不是 OnPointerDown 单次。
- Inspector:可挂多个回调;需把运行时参数传给方法时选 Dynamic,避免「静态绑定只带固定值」的坑。
- 代码:
AddListener注册,RemoveListener按委托移除,RemoveAllListeners清空;销毁按钮前若曾用匿名 lambda 注册,要记得配对清理,否则偶有悬挂引用(具体看项目生命周期)。
答题示例
在按钮上完整点完一次,抬起时触发 onClick。
Inspector 用 Dynamic 才能把滑条值等传进方法;代码里 AddListener,不用了 Remove。
参考文章
- 11.UGUI基础-组合控件-Button按钮控件
4. UGUI 里打图集主要想解决什么问题
题目
做 UGUI 时为什么要打图集?和 DrawCall(DC)之间怎么口头解释清楚?
深入解析
- 目的:把很多张小 Sprite 合并进少量大纹理,让一整块界面更可能 一次批次、少次提交画出来,减轻 CPU 侧排队、切换材质的开销。
- DC 口径:DC 常说成 CPU 通知 GPU 再来一笔绘制 的次数;碎图多、材质分裂,就容易把次数顶上去,表现为帧时间尖刺或掉帧。
- 边界:口语「n 张变 1 张就 1 个 DC」是教学简化;真机还要看 Canvas 是否切开、是否同一材质/同一图集引用 等。
答题示例
打图集是为了让一批 UI 少几次绘制提交,CPU 少忙活。
DC 太高会卡;图集把碎图合成大图是常规优化手段,但实际批次还看 Canvas 和材质。
参考文章
- 18.UGUI基础-图集制作
5. 什么时候用事件接口而不是只绑 Button.onClick
题目
已有 Button 时会用 On Click。那在什么需求下你会改用 IPointerDownHandler / IDragHandler 一类接口,或挂 EventTrigger?
深入解析
- UnityEvent 能兜住的:标准单击、Slider/Toggle 自带值变化等,先用组件自带列表最省事。
- 接口 / Trigger 上场:要 按下时长、拖拽轨迹、双击、滚轮、滚动区内精细指针逻辑,或 Image / RawImage 没有现成 OnClick 却要响应指针;接口在 同一脚本里写清状态机,EventTrigger 则适合 Inspector 配表 或与 面板脚本集中登记。
- 代价:脚本要挂在接收射线的对象上且一般要开 Raycast Target;触摸机上 Enter/Exit 的行为别当键鼠完全等价。
答题示例
标准点击用 Button;长按、拖、让纯图响应指针,用接口或 EventTrigger。
EventTrigger 就是少写几个接口文件、把 Entry 往列表里塞。
参考文章
- 19.UGUI进阶-UI事件监听接口
- 20.UGUI进阶-EventTrigger事件触发器
进阶题
1. UIElements、UGUI、IMGUI 大致怎么分工
题目
Unity 里经常听到 UIElements(UI Toolkit)、Unity UI(UGUI)、IMGUI 三套东西,从「做商业游戏界面」和「写编辑器工具」两个角度,你会怎么区分它们?
深入解析
- 叫法:官名 Unity UI,口语 UGUI 即同一套;主要面向运行时玩家点得到的游戏界面,不是做 Editor 窗口的主力。
- UGUI:运行时游戏 UI 的事实标准之一,Inspector 里拖组件、场景里摆层次,和相机、Canvas、EventSystem 一整套走。
- IMGUI:偏即时模式,在 Editor 里写工具、在运行时用
OnGUI做调试或极简界面还行;正式游戏 UI一般不用它扛大旗。 - UIElements / UI Toolkit:Unity 中后期强推的保留模式 UI,编辑器侧大量新功能用它;运行时是否采用要看团队版本与项目选型,和 UGUI 是并存关系,不是「学了 A 就不用 B」的简单替换。
回答时抓住:谁是给玩家点的游戏界面主力、谁是给策划程序在编辑器里用的、谁是历史包袱和调试向,就够使面试官听出你是在项目里做过事的。
答题示例
官名 Unity UI,口头说 UGUI;玩家点得到的游戏界面主力还是这套。
IMGUI 多为编辑器工具或调试;UI Toolkit 在编辑器侧越来越重要,和 UGUI 并行,选型看项目。
参考文章
- 1.概述
2. GraphicRaycaster 的 Blocking 在 Overlay 下为何常显得没用
题目
GraphicRaycaster 里有 Blocking Objects、Blocking Mask,为什么说在 Screen Space - Overlay 下它们基本不起作用?
深入解析
- Overlay 下整个 UI 画在屏幕最前,和场景里 3D 碰撞器的空间关系脱钩;教程里给的原话是:UI 永远在最前时,用 3D 碰撞器去「挡 UI 射线」这条链路不成立,所以 Blocking 相关项在覆盖模式下无效。
- 到了 Screen Space - Camera 或需要让 3D 与 UI 在同一套深度里算前前后后时,Blocking 才有设计意义。
- 面试加分:能顺带提到「真正要点还是要先搞清楚当前 Canvas 渲染模式」。
答题示例
Overlay 时 UI 直接盖在最上层,不按世界空间去和碰撞体挡射线,所以 Blocking 设了也白设。
Camera 模式才可能让 3D 挡在 UI 前之类的情况需要再看 Blocking;模式不对就别瞎调碰撞体掩码。
参考文章
- 5.UGUI基础-六大基础组件-GraphicRaycaster图形射线投射器组件
3. Text 叠在按钮上点不透怎么排
题目
界面上 Text 盖在 Button 上面,运行时发现点按钮没反应,很常见的原因之一是什么?怎么改?
深入解析
- Text 继承 Graphic,默认 Raycast Target 打开,射线会在文字区域被「截胡」,后面的 Button 收不到点击。
- 处理:关掉 Text 的 Raycast Target,或把文字做成 Button 子节点由 Button 统一接射线、或调整层级让可点区域不被纯展示 Text 挡住。
- 进阶可提:同类的 Image 纯底图也要养成「不交互就关 Raycast」的习惯,少一层误挡点击。
答题示例
Text 默认参与射线检测,把射线挡在字上就点不到下面按钮。
展示用文案把 Raycast Target 关掉,或者结构调整让 Button 吃到事件。
参考文章
- 9.UGUI基础-三大基础控件-Text文本控件
4. ScrollRect 里 Content 与滚动条引用要注意什么
题目
ScrollRect 的可滚范围主要由谁决定?若删掉预设的水平或垂直 Scrollbar,除了拆对象还要在组件上做什么?
深入解析
- Content 的 RectTransform 尺寸相对 Viewport 越大,能拖动的余量越多;Content 小于等于视口时本来也滚不动多少,配合 Visibility 可自动藏条。
- 原文点名:删掉滚动条后必须在 ScrollRect 把对应滚动条字段置空,否则易出异常或隐性问题;布局上把 Viewport 等铺满,避免还为滚动条留了缝。
- normalizedPosition
(0,1)一类可代码归位到边角,做背包重置列表时常用。
答题示例
能滚多远看 Content 比 Viewport 大多少。
删 Scrollbar 要在 ScrollRect 上空引用,viewport 拉满别留缝。
参考文章
- 16.UGUI基础-组合控件-ScrollView滚动视图控件
5. Sprite Packer 里 Legacy 模式和 Padding Power 是什么鬼
题目
Edit → Project Settings → Editor 里老版 Legacy Sprite Packer 和新的打包开关主要差在哪?Padding Power 数字大致怎么理解?
深入解析
- Legacy 行:多一个 Padding Power,管打包时 精灵之间、精灵与图集边 留多大缝,取值为 2 的 n 次方 像素量级,用来给过滤、采样留余量,减裂边和穿帮。
- Always Enabled 相对 Enabled For Builds:多了编辑模式下跑游戏前也会打,本地调 UI 时更容易和真机构建表现一致;只开 For Builds 则编辑器里未必先帮你打齐。
- 版本句:菜单名、是否 Legacy 以当前 Unity 文档为准;面试答「Legacy 多 padding、Always 会在进 Play 前打」即可。
答题示例
Legacy 多套一个 Padding Power,缝按 2 的幂来。
Always Enabled 编辑器运行前也会打包;只 For Builds 就偏上包体阶段。
参考文章
- 18.UGUI基础-图集制作
6. ScreenPointToLocalPointInRectangle 四个参数怎么填
题目
RectTransformUtility.ScreenPointToLocalPointInRectangle 的四个参数各是什么?拖拽里为什么常从 PointerEventData 里取摄像机?
深入解析
- rect:作为「本地空间原点」的那个
RectTransform,一般是拖动对象的父级或容器底。 - screenPoint:屏幕像素坐标,拖拽里直接用
eventData.position。 - cam:参与这次 UI 射线/绘制的
Camera;Screen Space - Camera 下必须对上渲染该 Canvas 的那台相机,否则点会飘;常用eventData.pressEventCamera或enterEventCamera。 - localPoint:
out到的 父 rect 本地 坐标,再赋给anchoredPosition或localPosition视锚点习惯而定。 - 比手写
position += delta更稳,因为统一走 RectTransform 数学。
答题示例
父 Rect、屏幕点、相机、out 本地点。
相机要从事件数据拿,和画 UI 的那台一致,不然坐标对不上。
参考文章
- 21.UGUI进阶-屏幕坐标转UI相对坐标
深度题
1. Scale With Screen Size 下三种 Screen Match Mode 怎么取舍
题目
CanvasScaler 选 Scale With Screen Size 后,Expand、Shrink、Match Width Or Height 大致各会带来什么画面结果?项目里怎么选?
深入解析
- Expand:缩放后整套 UI 仍完全落在安全区内,宁可上下左右留 黑边,适合「一条边也不能少」的界面稿。
- Shrink:尽量放大去贴满视口,宁可 裁掉 一部分边缘内容,适合强调铺满、可接受少量出框。
- Match Width Or Height:在参考分辨率与实机比例不一致时,偏向按宽度或按高度去算缩放,中间再辅以裁切或黑边,UI 元素相对尺寸更「钉死」,手游横竖屏要微调时常见用滑杆去靠宽或靠高。
- 没有万能默认值:听美术和策划要「必须全看见」还是「必须撑满」,再反推选 Expand 还是 Shrink;要兼顾多种长宽比再动 Match。
答题示例
Expand 宁可黑边也要整张 UI 露完;Shrink 宁可裁边也要铺满。
Match 是偏宽还是偏高去算缩放,横竖屏分歧大时常用。跟策美对齐是要裁还是要边再说。
参考文章
- 4.UGUI基础-六大基础组件-CanvasScaler画布缩放器组件
2. Image 四种 Image Type 各解决什么界面需求
题目
Simple / Sliced / Tiled / Filled 四种 Image Type 分别适合什么效果?Sliced 要额外在资源侧做什么?
深入解析
- Simple:整张贴图按比例缩放,适合形状简单、不需要九宫保护的图标。
- Sliced:九宫格,只拉中间、四角不穿帮;必须在 Sprite Editor 里设好 Border,否则和 Simple 拉糊没区别。
- Tiled:中间区域重复平铺,适合做底纹类填充。
- Filled:用 Fill Amount 控制可见比例,配合 Fill Method、Fill Origin、Clockwise 做血条、CD 圆环等进度表现。
答题示例
Simple 整图缩放;Sliced 九宫格要在 Sprite 上切边;Tiled 平铺;Filled 做进度裁剪。
Sliced 不开 border 九宫格就不生效。
参考文章
- 8.UGUI基础-三大基础控件-Image图片控件
3. InputField 的 onValueChanged 和 onEndEdit 何时触发
题目
InputField 里 onValueChanged 与 onEndEdit 分别在什么时机回调?做「实时搜索」和「提交再校验」各该听哪个?
深入解析
- onValueChanged(string):字符串每变一次就触发,包括逐字输入、删字、代码改
text,适合即时预览、字数提示、客户端过滤。 - onEndEdit(string):输入域失焦或完成一次提交(如按回车)时触发,适合整串校验、发请求、写存档,避免每个字符都请求。
- Inspector 绑方法需
string参数并选 Dynamic;与 Content Type、Character Limit 组合决定能输入什么。
答题示例
值一变就 onValueChanged;点别处或回车那种结束输入走 onEndEdit。
联想、实时提示走前者,确定再提交走后。
参考文章
- 13.UGUI基础-组合控件-InputField文本输入控件
4. 代码里怎么从 SpriteAtlas 取出一张子图
题目
运行时用代码加载 SpriteAtlas 并取其中一张 Sprite,要引哪个命名空间?GetSprite 传的字符串该和谁对齐?
深入解析
- 命名空间:
UnityEngine.U2D,类型是SpriteAtlas。 - 加载:示例用
Resources.Load<SpriteAtlas>("MyAtlas"),路径与Resources下相对路径一致(不带扩展名);实际项目常改 Addressables / AssetBundle,思路仍是先拿 Atlas 再GetSprite。 - 名字:
GetSprite("bk")里必须是图集中该 Sprite 的名称(与导入后 Sprite 名一致),否则取空或抛错;取出后可赋给Image.sprite。
答题示例
引用 UnityEngine.U2D,Load 出 SpriteAtlas 再 GetSprite。
字符串要和图集里的 Sprite 名一模一样,才能对上那张小图。
参考文章
- 18.UGUI基础-图集制作
5. CanvasGroup 三个开关各管什么、和子节点关系如何
题目
CanvasGroup 的 Alpha、Interactable、Blocks Raycasts 分别影响什么?Ignore Parent Groups 什么时候要勾?
深入解析
- Alpha:整棵子树 Graphic 的显式透明度乘子,做面板淡入淡出常用。
- Interactable:关掉后相当于整面板 不可交互,子控件收不到输入(与单独关每个 Selectable 相比是一把梭)。
- Blocks Raycasts:关掉后射线穿过该组,后面 UI 能接到点击;开则按层级正常挡。
- Ignore Parent Groups:勾选后本物体子树不再叠加父级 CanvasGroup 对 Alpha、可交互、挡射线的成组结果;嵌套弹窗要单独渐隐或与父层穿透策略分开时使用(层多时要和策划对齐)。
答题示例
Alpha 管显隐渐变;Interactable 管整组能不能点;Blocks Raycasts 管挡不挡射线。
Ignore Parent Groups 用来脱离父级 CanvasGroup 对这一套的成组影响。
参考文章
- 26.UGUI进阶-CanvasGroup画布组
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com