Cocos Creator中的UITransform 组件

UITransform(UI 变换组件)是 Cocos Creator 中所有 UI 节点的核心基础组件,它定义了 UI 元素在屏幕上的尺寸、位置和坐标系。理解它,是掌握 UI 系统最关键的一步。

当一个节点带有 UITransform 时,它就从普通节点变成了一个“UI 容器”或“UI 元素”,拥有了可测量、可布局的矩形区域。

📐 核心属性详解

UITransform 的属性主要分为两大类:基础属性高级属性

一、基础属性(在 Inspector 面板顶部)

这些是你最常直接操作的属性。

Content Size (内容尺寸)

定义 UI 节点

内容区域

的宽和高(像素)。这是 UI 节点的

内在大小

,是布局计算的基础。

(200, 100)

:创建一个宽 200,高 100 的矩形区域。

Anchor Point (锚点)

一个

归一化

的坐标点

(x, y)

,表示节点自身的“原点”或“抓手”。

(0, 0)

为左下角,

(1, 1)

为右上角。

(0.5, 0.5)

:中心点,常用于居中显示的元素。

(0, 1)

:左上角,常用于文本对齐。

Position (位置)

节点的

锚点

相对于其

父节点坐标系原点

的位置。

注意

:这个坐标是锚点所在的位置。

(100, 50)

:节点的锚点位于父节点坐标系中的

(100, 50)

处。

二、高级属性(在 Inspector 面板中折叠)

这些属性描述了更深层的布局机制,理解它们能解决很多布局疑难杂症。

Bounding Box (包围盒)

这是一个

只读

的派生属性,表示节点

在世界坐标系

中的实际矩形范围。它是

Content Size

经过

位置、旋转、缩放和锚点

变换后的最终结果。

点击检测、对齐、裁剪

都依赖它。

Content (内容区)

Content Size

定义的原始矩形区域,不受节点旋转、缩放和位置影响,是

局部坐标系

下的基准。

为了直观地理解 Content Size, Anchor Point, PositionBounding Box 之间的关系,请看下面的图示:

🎯 为什么需要 UITransform?核心作用

UITransform 是 UI 系统运作的“尺子”和“坐标纸”:

  1. 提供布局基准Content SizeWidget(对齐组件)、Layout(布局组件)计算位置和尺寸的绝对依据。
  2. 定义交互边界Bounding BoxButtonToggle 等 UI 组件检测触摸或点击事件的区域。
  3. 管理渲染层级:UITransform 的层级影响其子节点的渲染和事件顺序(结合 Canvas 组件)。
  4. 作为容器:它是 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,而不是自己写循环计算位置。

⚠️ 常见问题与调试

  1. 为什么我的 Content Size 改不动?最常见原因:该节点上有 Widget 组件,并且同时勾选了左右对齐或上下对齐。解决方案是禁用 Widget,或只启用单边对齐。其他原因:父节点有 Layout 组件且处于活动状态,Sprite 或 Label 的尺寸模式为 CUSTOM 等。检查并调整这些组件的设置。
  2. 如何调试 Bounding Box?可以在 update 中绘制调试矩形,或者临时给节点添加一个 Graphics 组件,根据 getBoundingBoxToWorld 计算出的顶点绘制一个线框,直观地看到它的实际范围。
  3. 锚点 (0.5, 0) 是什么意思?表示锚点位于节点底边的中点。当你改变节点的 Position 时,移动的就是这个底边中点。这在制作血条、进度条时非常有用。

总而言之,UITransform 是 UI 系统的基石。熟练掌握它的属性,理解 ContentBounding Box 的区别,并了解它与其他组件的协作关系,将让你在构建 Cocos Creator UI 时思路清晰,游刃有余。如果你在实现某个具体 UI 效果(如进度条、自适应面板)时遇到问题,我可以提供更具体的配置方案。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务