跳转到内容

遮罩与安全区

UIMask

将所有实体裁剪到父级 UIRect 边界内。拥有 UIMask 的实体本身不会被裁剪 — 只有其后代会被裁剪。

前置组件: 被遮罩的实体必须有 TransformUIRect

属性

属性类型默认值说明
enabledbooleantrue是否启用裁剪
modeMaskModeScissor遮罩技术(见下文)

MaskMode

模式说明
Scissor0GPU 裁剪测试 — 快速,仅支持轴对齐矩形
Stencil1模板缓冲 — 支持任意形状和嵌套

如何选择:

  • Scissor — 适用于简单矩形容器,如滚动视图、面板、卡片列表。速度快但只支持轴对齐矩形。
  • Stencil — 需要非矩形遮罩(圆形头像、自定义形状)或需要嵌套遮罩时使用(支持最多 255 层嵌套)。开销稍大。

在编辑器中设置

  1. 选择或创建一个带 UIRect 的 UI 实体(UIRect 定义裁剪范围)
  2. 在 Inspector 中添加 UIMask 组件
  3. 选择 ScissorStencil 模式
  4. 该实体下添加的所有子实体都会被裁剪到其边界内

在代码中设置

import { UIMask } from 'esengine';
// 创建遮罩容器
const panel = world.spawn();
world.insert(panel, UIRect, {
anchorMin: { x: 0.1, y: 0.1 },
anchorMax: { x: 0.9, y: 0.9 },
});
world.insert(panel, UIMask, { enabled: true, mode: 0 /* Scissor */ });
// 子内容 — 自动被裁剪
const content = world.spawn();
world.setParent(content, panel);
world.insert(content, Sprite, { texture: myTexture });

嵌套遮罩

Scissor 遮罩与父级 Scissor 做交集 — 子级 Scissor 遮罩产生两者的重叠矩形。

Stencil 遮罩支持真正的嵌套:每一层获得独立的模板引用值,子实体根据父级模板进行测试。最多支持 255 层嵌套。

Root (UIMask Stencil)
├── Header (裁剪到 Root)
└── Body (UIMask Stencil) ← 嵌套遮罩
├── Item 1 (裁剪到 Body ∩ Root)
└── Item 2 (裁剪到 Body ∩ Root)

SafeArea

自动适配设备安全区域(刘海、圆角、状态栏)。该组件通过调整 UIRect.offsetMinUIRect.offsetMax 来将元素从不安全边缘收缩。

前置组件: 实体必须有 UIRect

属性

属性类型默认值说明
applyTopbooleantrue从顶部边缘收缩(状态栏、刘海)
applyBottombooleantrue从底部边缘收缩(Home 指示条)
applyLeftbooleantrue从左侧边缘收缩(横屏刘海)
applyRightbooleantrue从右侧边缘收缩(横屏刘海)

工作原理

  1. SafeAreaPlugin 在启动时和窗口大小变化时读取设备安全区域边距
  2. 边距根据画布宽高比从屏幕像素缩放到世界单位
  3. 每帧(PreUpdate),插件将缩放后的边距应用到每个带 SafeArea 的实体的 UIRect.offsetMin / UIRect.offsetMax

典型用法

创建全屏容器并添加 SafeArea,将所有 UI 内容放在其中:

Canvas (全屏)
└── SafeArea 容器 (UIRect: 锚点 0,0 → 1,1) ← 在这里添加 SafeArea
├── HUD
├── 分数
└── 控制按钮

在编辑器中: 在根 UI 面板上添加 SafeArea。将锚点设为拉伸(0,0 → 1,1)。所有子元素将在安全区域内布局。

在代码中:

import { SafeArea } from 'esengine';
const safeContainer = world.spawn();
world.insert(safeContainer, UIRect, {
anchorMin: { x: 0, y: 0 },
anchorMax: { x: 1, y: 1 },
});
world.insert(safeContainer, SafeArea, {
applyTop: true,
applyBottom: true,
applyLeft: true,
applyRight: true,
});

选择性应用边缘

你可能只需要部分边缘的安全区域。例如,底部导航栏只需要底部安全区:

world.insert(navBar, SafeArea, {
applyTop: false,
applyBottom: true,
applyLeft: true,
applyRight: true,
});

平台支持

平台边距获取方式
WebCSS env(safe-area-inset-*) 通过计算样式变量 --sat--sab--sal--sar
微信小游戏wx.getSystemInfoSync() 读取 safeArea 字段,窗口大小变化时自动更新
桌面端返回零边距(无安全区域问题)

插件注册

uiMaskPluginsafeAreaPlugin 由引擎自动注册,无需手动设置。

下一步