视觉树保存窗口中的所有视觉元素。它是由称为视觉元素的轻量级节点组成的对象图。
这些节点在 C# 堆上分配(手动进行分配或通过从 UXML 模板文件加载 UXML 资源的方式进行分配)。
每个节点都包含布局信息、其绘制和重绘选项以及节点如何响应事件。
VisualElement
VisualElement 是视觉树中所有节点的公共基类。VisualElement 基类包含样式、布局数据、本地变换、事件处理程序等的属性。
VisualElement 有若干子类,包括专门的控件,它们定义了其他行为和功能。VisualElement 可包含子元素。
不需要从 VisualElement 基类进行派生来使用 UIElements。可以通过样式表和事件回调来自定义 VisualElement 的外观和行为。
连接
视觉树的根对象称为面板。新元素在连接到面板之前将被忽略。可以向现有元素添加元素来将用户界面连接到面板。
为了验证 VisualElement 是否已连接到面板,可以测试此元素的 panel 属性。未连接视觉元素时,测试将返回 null。
可在 UnityEditor.UIElements 命名空间中使用容器对象的 rootVisualElement 元素将新元素添加到树中。
绘制顺序
按以下顺序绘制视觉树中的元素:
更改绘制顺序的唯一方法是在父项中重新排序 VisualElement 对象。
位置、变换和坐标系
不同的坐标系定义如下:
- 世界坐标系:坐标相对于面板空间。面板是视觉树中的最高层级元素。
- 局部坐标系:坐标相对于元素本身。
布局系统会计算每个元素 VisualElement.layout 属性(Rect 类型)。
layout.position 表示为相对于其父项坐标空间的像素。虽然可以直接为 layout.position 赋值,但建议您使用样式表和布局系统来定位元素。
每个 VisualElement 也有一个 layout.transform 属性(ITransform 类型)可相对于父元素对元素进行定位。默认情况下,transform 是标识。
VisualElement.layout.position 和 VisualElement.layout.transform 属性用于定义如何在局部坐标系和父坐标系之间进行转换。
VisualElementExtensions 静态类提供了以下扩展方法在坐标系之间转换点和矩形:
- WorldToLocal 将 Vector2 或 Rect 从 Panel 空间转换为元素内的参照。
- LocalToWorld 将 Vector2 或 Rect 转换为 Panel 空间参照。
- ChangeCoordinatesTo 将 Vector2 或 Rect 从一个元素的局部空间转换为另一个元素的局部空间。
视觉树层级视图
例如,在上图中,树的排列如下:
- Panel
- 标签部分(称为 DockArea 并标记为“Coordinates”)
- 蓝色 VisualElement 充当根(称为“rootVisualContainer”)
- 红色 VisualElement 充当按钮的父级(“red container”,即红色容器)
从面板的角度来看:
- 无论参照如何,面板的原点都是 (0, 0)
- 根的原点在世界空间中为 (0, 22)
- 红色容器的原点在世界空间中为 (100, 122)。它的 position 属性(在 layout 属性中定义)设置为 (100, 100),因为它相对于它的父项:根容器。
- 按钮的原点在世界空间中为 (100, 122)。它的 position 属性(在 layout 属性中定义)设置为 (0, 0),因为它相对于它的父项:红色容器。
元素的原点是其左上角。
使用 worldBound 属性,同时考虑 VisualElement 的祖先的变换和位置,可以检索该元素的窗口空间坐标。