本页介绍了在 视觉树一个由轻量级节点组成的对象图,它保存了窗口或面板中的所有元素。它定义了使用 UI 工具包构建的每个 UI。
参见 术语表 中管理元素的最佳实践。
元素池化是指保留可能以后会重新创建的元素,而不是每次都使用 new()
创建元素并将其释放。
重要的是要完全控制池化的所有元素,并确保在将它们放回池之前正确重置它们。否则,池化系统可能会变得不稳定且麻烦。例如,如果您在注册事件回调或同时设置内部非序列化状态时池化元素,则无法清理元素。
为了保持 视觉元素视觉树的一个节点,它实例化或派生自 C# VisualElement
类。您可以设置外观、定义行为,并将其显示在屏幕上作为 UI 的一部分。 更多信息
参见 术语表 的数量较少,请尽可能使用 ListView。 ListView 池化元素,并在用户滚动时回收元素。
或者,您可以实现自己的池和回收机制,类似于 ListView,并使用以下方法管理可见区域
GeometryChangedEvent
VisualElement.layout
属性当您使用 VisualElement.RemoveFromHierarchy()
从层次结构中删除元素并消除对它的引用时,该元素将被垃圾回收。这将 CPU 和 GPU 成本降低到零,并释放大量内存。但是,重新创建元素并将其重新加载到层次结构中是一个缓慢且昂贵的操作。为了避免这种情况,您可以在层次结构中预先创建元素,使用 USS 样式 属性来隐藏它们,并且仅在必要时才显示它们。虽然应用样式通常更快,但如果同时创建大量元素,可能会导致内存使用量增加。
以下是隐藏元素的不同方法及其对处理器和内存使用量的影响。
visibility: hidden;
隐藏使用这种方法,后代可以覆盖 visibility
样式。
下表介绍了使用 visibility
样式隐藏或显示视觉元素时的单帧成本的不同方面
方面 | visibility: hidden; |
visibility: visible; |
---|---|---|
样式 | 为元素及其后代进行评估,以传播可见性。 | 为它及其后代进行评估,以传播可见性。 |
布局数据 | 保留 | 无 |
渲染命令 | 删除并释放 | 重新创建并重新插入到命令链中。 |
网格 | 计划进行释放。 | 重新细分 |
下表介绍了使用 visibility
样式隐藏视觉元素时,CPU 和 GPU 的每帧行为
处理器 | 方面 | 每帧行为 |
---|---|---|
CPU | 样式 | 完全评估到元素及其后代。 |
布局数据 | 更新 | |
细分 | 最小的影响,只涉及 模板遮罩网格溢出隐藏,具有圆角或矢量图像背景。 参见 术语表(如果适用)。 |
|
渲染命令 | 没有绘制常规可见几何体的命令。但是,模板遮罩网格仍然会渲染以从模板中推送或弹出,确保潜在的可见后代被遮罩。 | |
GPU | 网格 | 模板遮罩网格上的顶点和片段着色。 |
opacity: 0;
隐藏使用这种方法,如果内容在 视口用户在屏幕上看到应用程序的区域。
参见 术语表 中,GPU 使用量可能很高,因为片段 着色器在 GPU 上运行的程序。 更多信息
参见 术语表 会处理所有元素,这可能会导致大量的过度绘制。
下表介绍了使用 opacity
样式隐藏或显示视觉元素时的单帧成本
操作 | 单帧成本 |
---|---|
opacity: 0; |
第一次将 opacity 设置为除 1 以外的值时,UI(用户界面) 允许用户与您的应用程序进行交互。Unity 目前支持三个 UI 系统。 更多信息参见 术语表 工具包渲染器会修改顶点以加速在 GPU 上应用不透明度。这会触发一次性的、最小的 CPU 成本。虽然通常可以忽略不计,但如果元素具有大量后代或要修改的顶点很多,则此成本可能会变得很明显。除非元素从视觉树中删除并重新添加,否则不会再次产生此成本。 |
opacity: 1; |
无 |
下表介绍了使用 opacity
样式隐藏视觉元素时,CPU 和 GPU 的每帧行为
处理器 | 方面 | 每帧行为 |
---|---|---|
CPU | 样式 | 完全评估到元素及其后代。 |
细分 | 正常运行并响应更改。 | |
渲染命令 | 执行 | |
GPU | 网格 | 顶点着色器在渲染 3D 模型时,在模型的每个顶点上运行的程序。 更多信息 参见 术语表 的运行方式就好像 visibility 设置为 1 一样。类似地,片段着色器也像 visibility 为 1 时那样工作。这在 GPU 繁忙的项目中可能是有害的,因为它会导致过度绘制。 |
display: none;
隐藏使用这种方法,元素的行为就像它从布局树中删除一样,这可能会影响其他元素的布局。
下表介绍了使用 display
样式隐藏或显示视觉元素时的单帧成本的不同方面
方面 | display: none; |
display: flex; |
---|---|---|
布局数据 | 可能会重新计算其他元素的布局。 | 处理待处理的布局更改。 |
渲染命令/网格 | 为受布局更改影响的元素重新生成。 |
|
下表介绍了使用 display
样式隐藏视觉元素时,CPU 的每帧行为。请注意,没有 GPU 成本。
方面 | 每帧行为 |
---|---|
布局数据 | 保留,但可能会失效并且没有更新。 |
渲染命令 | 虽然保留,但在执行期间可以跳过。跳过它们的方式非常便宜,但并不完全免费。成本与命令数量成正比。 |
网格 | 保留,但可能会失效并且没有更新。 |
您可以使用 translate: -5000px -5000px;
与 DynamicTransform
使用提示结合使用,将元素移出视口。几何图形保持完全活动,因此当您将元素带回到屏幕上时,CPU 使用量最少。但是,GPU 会继续处理顶点,这在某些情况下可能是可以接受的。
变换被计算并上传到 GPU 内存中,这通常很快。
下表介绍了通过将视觉元素平移到视口之外来隐藏它时,CPU 和 GPU 的每帧行为
处理器 | 方面 | 每帧行为 |
---|---|---|
CPU | 样式 | 更新 |
布局数据 | 更新 | |
绘制调用 | 执行 | |
GPU | 网格 | 顶点被着色。 |
当您使用 VisualElement.RemoveFromHierarchy()
方法从层次结构中删除元素时,您会释放 CPU 和 GPU 内存,从而消除任何计算成本。
下表介绍了通过从层次结构中删除视觉元素来隐藏或显示它时的单帧成本
方面 | 删除 | 添加 |
---|---|---|
样式 | 无 | 为子树更新。 |
布局 | 无 | 为子树以及可能的其他元素重新计算。 |
渲染命令/网格 | 为受布局更改影响的元素重新生成。 |
|
下表总结了使用不同方法隐藏元素后的内存使用量
处理器 | 方面 | visibility:hidden; |
opacity:0; |
display:None; |
平移到视口之外 | 从层次结构中删除 |
---|---|---|---|---|---|---|
CPU | 样式 | 保留 | 保留 | 保留 | 保留 | 释放 |
布局 | 保留 | 保留 | 保留 | 保留 | 保留[1] | |
渲染命令/网格 | 释放 | 保留 | 保留 | 保留 | 释放 | |
GPU | 网格 | 释放 | 保留 | 保留 | 保留 | 释放 |
布局内存被保留,因为它仍然为元素保留。当 VisualElement 被垃圾回收时,布局内存将返回到池中,使其可供其他元素使用。 ↩