可视树保存窗口中的所有可视元素。它是由轻量级节点组成的对象图,称为视觉元素(visual elements)。
这些节点在C#堆上分配,可以手动或通过从UXML模板文件加载UXML资产。
每个节点都包含布局信息,其绘图和重绘选项,以及节点如何响应事件。
VisualElement(可视元素)
VisualElement是可视树中所有节点的公共基类。 VisualElement基类包含样式,布局数据,本地变换,事件处理程序等属性。
VisualElement有几个子类,用于定义其他行为和功能,包括专用控件。 VisualElement可以有子元素。
您不需要从VisualElement基类派生来使用UIElements。您可以通过样式表和事件回调自定义VisualElement的外观和行为。
Connectivity(连接)
可视树的根对象称为面板(Panel)。如果可视元素最终没有连接到面板,那么它将被忽略。您可以向现有元素添加子元素,以将您的界面加入到面板。
要验证VisualElement是否已连接到面板,您可以测试此元素的panel属性。未连接到可视元素时,测试返回null。
您需要使用UnityEditor.UIElements命名空间中的容器对象rootVisualElement元素来向树中添加新元素。
Drawing order(绘图顺序)
可视树中的元素按以下顺序绘制:
- 父元素在子元素前被绘制
- 子元素按照其在兄弟节点之间排序被绘制
更改其绘制顺序的唯一方法是在其父级中重新排序VisualElement对象。
Position, transforms, and coordinate systems(定位,变换和坐标系统)
不同的坐标系定义如下:
World:坐标是相对Panel空间的,注意Panel是可视树中的最高元素。
Local:坐标是相对于元素本身的。
布局系统为每个元素计算VisualElement.layout属性(类型为Rect)。
layout.position被表示为相对于其父级坐标空间中的像素。虽然您可以直接为layout.position指定值,但建议您使用样式表和布局系统来定位元素。
每个VisualElement还有一个layout.transform属性(ITransform类型),根据它将本元素相对于其父元素定位。默认情况下,transform就是自身{ITransform是一个接口,定义了子类须实现的position、rotation、scale等属性}。
VisualElement.layout.position和从VisualElement.layout.transform实现的其它属性定义了如何在本地坐标系和父坐标系之间进行变换。
VisualElementExtensions静态类提供以下扩展方法,用于转换坐标系之间的顶点和矩形:
- WorldToLocal将Vector2或Rect从Panel空间转换为元素的局部空间
- LocalToWorld将Vector2或Rect从元素的局部空间转换为Panel空间
- ChangeCoordinatesTo将Vector2或Rect从一个元素的局部空间转换为另一个元素的局部空间。
![Visual tree hierarchy](https://img-blog.csdnimg.cn/20190804213204195.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FuZHJld0Zhbg==,size_16,color_FFFFFF,t_70)
例如,在上图中,树的排列如下:
Panel
- 标签(Tab)部分(称为DockArea并标记为“Coordinates”)
- 蓝色
VisualElement
作为根元素 (称为“rootVisualContainer”)- 红色
VisualElement
作为Button
的父级 (“red container”)Button
- 红色
从顶点坐标的角度来看整个Panel:
- 无论参考如何,Panel的原点都是(0,0)
- 根元素的原点是世界空间中的(0,22)
- 红色容器的原点是世界空间中的(100,122)。它的position属性(在layout属性中定义)设置为(100,100),因为它相对于其父级:根容器。
- 按钮的原点是世界空间中的(100,122)。它的position属性(在layout属性中定义)设置为(0,0),因为它相对于其父级:红色容器。
元素的原点是它的左上角。
可以使用worldBound属性来检查可视元素的窗口空间坐标,它计算时已经考虑了所有父层次的变换和位置。