Cocos Creator中的UITransform 组件
UITransform(UI 变换组件)是 Cocos Creator 中所有 UI 节点的核心基础组件,它定义了 UI 元素在屏幕上的尺寸、位置和坐标系。理解它,是掌握 UI 系统最关键的一步。
当一个节点带有 UITransform 时,它就从普通节点变成了一个“UI 容器”或“UI 元素”,拥有了可测量、可布局的矩形区域。
📐 核心属性详解
UITransform 的属性主要分为两大类:基础属性 和 高级属性。
一、基础属性(在 Inspector 面板顶部)
这些是你最常直接操作的属性。
Content Size (内容尺寸) | 定义 UI 节点 内容区域 的宽和高(像素)。这是 UI 节点的 内在大小 ,是布局计算的基础。 |
:创建一个宽 200,高 100 的矩形区域。 |
Anchor Point (锚点) | 一个 归一化 的坐标点
,表示节点自身的“原点”或“抓手”。
为左下角,
为右上角。 |
:中心点,常用于居中显示的元素。
:左上角,常用于文本对齐。 |
Position (位置) | 节点的 锚点 相对于其 父节点坐标系原点 的位置。 注意 :这个坐标是锚点所在的位置。 |
:节点的锚点位于父节点坐标系中的
处。 |
二、高级属性(在 Inspector 面板中折叠)
这些属性描述了更深层的布局机制,理解它们能解决很多布局疑难杂症。
Bounding Box (包围盒) | 这是一个 只读 的派生属性,表示节点 在世界坐标系 中的实际矩形范围。它是 Content Size 经过 位置、旋转、缩放和锚点 变换后的最终结果。 点击检测、对齐、裁剪 都依赖它。 |
Content (内容区) |
定义的原始矩形区域,不受节点旋转、缩放和位置影响,是 局部坐标系 下的基准。 |
为了直观地理解 Content Size, Anchor Point, Position 和 Bounding Box 之间的关系,请看下面的图示:
🎯 为什么需要 UITransform?核心作用
UITransform 是 UI 系统运作的“尺子”和“坐标纸”:
- 提供布局基准:
Content Size是Widget(对齐组件)、Layout(布局组件)计算位置和尺寸的绝对依据。 - 定义交互边界:
Bounding Box是Button、Toggle等 UI 组件检测触摸或点击事件的区域。 - 管理渲染层级:UITransform 的层级影响其子节点的渲染和事件顺序(结合
Canvas组件)。 - 作为容器:它是
Sprite(精灵)、Label(标签)等可视化组件的承载者,决定了这些组件绘制的“画布”大小和位置。
🔧 怎么用?典型应用场景与代码
场景1:精确控制UI元素的大小和位置
这是最基本也是最核心的用法。
import { _decorator, Component, Node, UITransform, Vec3 } from 'cc';
// 注意:从 'cc' 模块导入,且不再有 'v3' 辅助函数
@ccclass('UIControl')
export class UIControl extends Component {
start() {
const uiTrans = this.getComponent(UITransform)!; // 使用非空断言
// 1. 动态设置大小 - 方法保持不变
uiTrans.setContentSize(200, 60);
// 2. 设置锚点 - 方法保持不变
uiTrans.setAnchorPoint(0.5, 0.5);
// 3. 必须使用 new Vec3() 创建向量
this.node.setPosition(new Vec3(0, 0, 0));
}
}
场景2:计算和检测点击区域
判断触摸点是否在一个 UI 节点内。
import { _decorator, Component, Node, UITransform, input, Input, EventTouch, Vec3 } from 'cc';
@ccclass('CheckClick')
export class CheckClick extends Component {
private uiTrans: UITransform | null = null;
onLoad() {
this.uiTrans = this.getComponent(UITransform);
// 注册触摸事件
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
}
onTouchStart(event: EventTouch) {
if (!this.uiTrans) return;
const touchPos = event.getUILocation();
// 方法1:使用 convertToNodeSpaceAR
const worldPos = new Vec3(touchPos.x, touchPos.y, 0);
const localPos = this.uiTrans.convertToNodeSpaceAR(worldPos);
const halfWidth = this.uiTrans.width / 2;
const halfHeight = this.uiTrans.height / 2;
if (Math.abs(localPos.x) <= halfWidth && Math.abs(localPos.y) <= halfHeight) {
console.log('点击到了UI元素内部!');
}
// 方法2:使用 BoundingBox
// 【注意】3.x 中获取世界包围盒的API通常是 getWorldBounds()
// 但这里判断包含需要转换坐标,更常用的实践是使用方法1
// 以下为更通用的点击检测方法:
const uiPos = new Vec3();
this.uiTransform!.convertToNodeSpaceAR(worldPos, uiPos); // 使用out参数版本
}
onDestroy() {
// 记得移除事件监听
input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
}
}
场景3:实现自定义的布局或排列
手动计算子节点位置。
import { _decorator, Component, Node, UITransform } from 'cc';
@ccclass('SimpleLayout')
export class SimpleLayout extends Component {
start() {
const parentTrans = this.getComponent(UITransform);
const children = this.node.children;
// 假设我们要将子节点垂直排列,间距为 10
let currentY = 0;
for (let i = 0; i < children.length; i++) {
const child = children[i];
const childTrans = child.getComponent(UITransform);
// 设置子节点锚点在顶部中心 (0.5, 1),便于从上向下排列
childTrans.setAnchorPoint(0.5, 1);
// 设置子节点的局部位置
child.setPosition(new Vec3(0, currentY, 0));
// 下一个子节点的起始 Y 坐标 = 当前Y - 当前子节点高度 - 间距
currentY -= (childTrans.height + 10);
}
}
}
💡 与其他UI组件的关系与配置技巧
- 与 Widget(对齐组件):Widget 依赖 Content Size 来计算如何相对于父节点对齐。如果 Widget 设置了同时左对齐和右对齐,它就会覆盖(驱动)Content Size。这就是为什么手动修改 Content Size 有时会失效的原因。技巧:如果需要手动控制大小,请将 Widget 的 isAlignLeft/isAlignRight 等对齐选项只勾选一边,或通过代码控制。
- 与 Sprite(精灵组件)/ Label(标签组件):这些渲染组件本身会有一个默认大小(如图片像素或文本内容)。技巧:通常将 Sprite 或 Label 组件的 Size Mode 设置为 TRIMMED(自适应内容),这样 UITransform 的 Content Size 就会自动调整为内容大小,省去手动计算的麻烦。
- 与 Layout(布局组件):Layout 组件会读取子节点的 Content Size,并根据规则自动排列它们。技巧:如果子节点大小不一又想排列整齐,可以利用 Layout,而不是自己写循环计算位置。
⚠️ 常见问题与调试
- 为什么我的 Content Size 改不动?最常见原因:该节点上有 Widget 组件,并且同时勾选了左右对齐或上下对齐。解决方案是禁用 Widget,或只启用单边对齐。其他原因:父节点有 Layout 组件且处于活动状态,Sprite 或 Label 的尺寸模式为 CUSTOM 等。检查并调整这些组件的设置。
- 如何调试 Bounding Box?可以在 update 中绘制调试矩形,或者临时给节点添加一个 Graphics 组件,根据 getBoundingBoxToWorld 计算出的顶点绘制一个线框,直观地看到它的实际范围。
- 锚点 (0.5, 0) 是什么意思?表示锚点位于节点底边的中点。当你改变节点的 Position 时,移动的就是这个底边中点。这在制作血条、进度条时非常有用。
总而言之,UITransform 是 UI 系统的基石。熟练掌握它的属性,理解 Content 与 Bounding Box 的区别,并了解它与其他组件的协作关系,将让你在构建 Cocos Creator UI 时思路清晰,游刃有余。如果你在实现某个具体 UI 效果(如进度条、自适应面板)时遇到问题,我可以提供更具体的配置方案。