RectTransform 是 Unity UGUI 系统的核心组件,继承自 Transform。虽然它保留了位置、旋转和缩放属性,但其定位逻辑与普通 3D 物体截然不同。
很多开发者在处理 UI 适配(分辨率变化)时感到痛苦,根源往往是对 Anchors(锚点)、Pivot(轴心) 和 SizeDelta 的数学定义理解不深。
transform.position 指的就是 Pivot 在世界空间的位置。理解 RectTransform 最关键的一点是:根据 Anchors 是否重合,属性面板显示的变量含义会完全改变!
当 Anchor Min 等于 Anchor Max 时(例如都在中心),锚点是一个点。
当 Anchor Min 不等于 Anchor Max 时(例如 Min(0,0) Max(1,0) 底边拉伸),锚点形成一个矩形区域。
这是代码控制 UI 时最大的坑。
sizeDelta 的真相很多人以为 rectTransform.sizeDelta 就是宽高。大错特错!
sizeDelta 等于 宽高。sizeDelta 代表相对于锚点的距离差。
sizeDelta 为 (0,0) 时,代表填满父级。sizeDelta 为 (100, 100),意味着比父级大 100像素!(负边距)。offsetMin 和 offsetMax这两个属性是通用的,无论什么模式都能用。
offsetMin: 对应 (Left, Bottom) 的角相对于锚点的位移。offsetMax: 对应 (Right, Top) 的角相对于锚点的位移。实战技巧:代码设置全屏拉伸
public static void StretchToFill(RectTransform rt) {
rt.anchorMin = Vector2.zero; // 左下
rt.anchorMax = Vector2.one; // 右上
rt.pivot = new Vector2(0.5f, 0.5f);
// 将边距设为0,贴合父级
rt.offsetMin = Vector2.zero; // Left, Bottom = 0
rt.offsetMax = Vector2.zero; // Right, Top = 0
// 或者: rt.sizeDelta = Vector2.zero;
}
不要自己算坐标!不要自己算坐标!不要自己算坐标!
Unity 提供了 RectTransformUtility 处理复杂的 Pivot 和 Canvas 缩放。
| API | 作用 | 典型场景 |
|---|---|---|
ScreenPointToLocalPointInRectangle |
屏幕点 -> 局部点 | 鼠标点击 UI、物体飞向 UI |
WorldToScreenPoint |
世界(UI) -> 屏幕 | UI 坐标转回屏幕 (跨 Canvas) |
ScreenPointToWorldPointInRectangle |
屏幕点 -> 世界(UI) | 拖拽物体跟随鼠标 |
FlipLayoutOnAxis |
翻转布局 | 镜像 UI |
PixelAdjustPoint |
像素对齐 | 消除 UI 模糊 |
Camera 参数?null),因为 UI 直接渲染在屏幕上。canvas.worldCamera),因为此时 UI 是 3D 世界的一部分,受透视影响。这是一个极其高频的需求。
public class HealthBarFollow : MonoBehaviour {
public Transform target3D; // 3D 目标 (头顶)
public RectTransform healthBarUI; // UI 元素
public Canvas canvas; // 所在的 Canvas
public Vector3 offset = new Vector3(0, 2.0f, 0); // 头顶偏移量
void LateUpdate() {
if (target3D == null) return;
// 1. 3D 世界坐标 -> 屏幕坐标
Vector3 screenPos = Camera.main.WorldToScreenPoint(target3D.position + offset);
// 2. 屏幕坐标 -> UI 局部坐标
// 处理 Canvas 缩放模式 (Scale With Screen Size) 的关键步骤
Vector2 localPos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
canvas.transform as RectTransform,
screenPos,
canvas.worldCamera, // Overlay模式传null
out localPos
);
// 3. 应用坐标
healthBarUI.anchoredPosition = localPos;
}
}
处理 iPhone 刘海屏或挖孔屏。
public class SafeAreaAdapter : MonoBehaviour {
RectTransform panel;
void Awake() {
panel = GetComponent<RectTransform>();
ApplySafeArea();
}
void ApplySafeArea() {
Rect safeArea = Screen.safeArea;
// 将 Safe Area 转换为归一化锚点 (0~1)
Vector2 anchorMin = safeArea.position;
Vector2 anchorMax = safeArea.position + safeArea.size;
anchorMin.x /= Screen.width;
anchorMin.y /= Screen.height;
anchorMax.x /= Screen.width;
anchorMax.y /= Screen.height;
// 应用给全屏 Panel
panel.anchorMin = anchorMin;
panel.anchorMax = anchorMax;
}
}
将一个 UI 元素(如物品栏里的图标)从 Canvas A 移动到 Canvas B,或者让 Canvas B 里的特效跟随 Canvas A 里的按钮。
难点:
Screen Space - Overlay (无 Camera)。Screen Space - Camera (有 Camera, 且距离不同)。Scale Factor 可能不同。通用解决方案: 使用 屏幕坐标 (Screen Space) 作为绝对中介。
/// <summary>
/// 将 sourceRect (在 sourceCanvas 下) 的中心点位置,转换为 targetCanvas 下的局部坐标
/// </summary>
public static Vector2 ConvertUiPosition(RectTransform sourceRect, Canvas sourceCanvas, RectTransform targetParent, Canvas targetCanvas) {
// 1. 获取源 UI 的屏幕坐标
Vector3 screenPos;
Camera sourceCam = sourceCanvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : sourceCanvas.worldCamera;
// WorldToScreenPoint 处理了 Camera 模式下的透视和深度
// 如果是 Overlay,sourceRect.position 本身就是屏幕像素坐标,但用此 API 更安全通用
screenPos = RectTransformUtility.WorldToScreenPoint(sourceCam, sourceRect.position);
// 2. 将屏幕坐标转为目标 Canvas 的局部坐标
Vector2 localPos;
Camera targetCam = targetCanvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : targetCanvas.worldCamera;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
targetParent,
screenPos,
targetCam,
out localPos
);
return localPos;
}
// 使用示例: 金币从背包(Overlay)飞到世界UI(Camera)
void Update() {
Vector2 targetPos = ConvertUiPosition(inventoryIcon, inventoryCanvas, worldEffectContainer, worldCanvas);
flyingCoin.anchoredPosition = Vector2.Lerp(flyingCoin.anchoredPosition, targetPos, Time.deltaTime * 5);
}
RectTransform 的变动(Re-layout)是非常昂贵的,它会触发布局系统的重建。
LayoutGroup:
VerticalLayoutGroup, GridLayoutGroup 等自动布局组件性能开销大。Pixel Perfect 选项会增加计算量,非像素风游戏通常不需要开启。| 我想改变… | 模式 | 使用属性 |
|---|---|---|
| 绝对位置 | 点模式 | anchoredPosition |
| 固定宽高 | 点模式 | sizeDelta |
| 贴边距离 | 拉伸模式 | offsetMin (左下), offsetMax (右上) |
| 全屏铺满 | 任意 | anchorMin=0, anchorMax=1, offsetMin/Max=0 |
| 鼠标跟随 | 任意 | RectTransformUtility.ScreenPointToLocalPointInRectangle |