Unity3D :视觉树
推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
视觉树
UI 工具包中最基本的构建块是视觉元素。视觉元素被组织为具有父子关系的层级结构树。下图显示了层级结构树的简化示例,以及 UI 工具包中的渲染结果。
视觉元素
类是可视化树中所有节点的基础。基类包含样式、布局数据和事件处理程序等属性。视觉元素可以有子级和后代视觉元素。例如,在上图中,第一个可视元素有三个子可视元素:、 和 。VisualElementBoxLabelCheckboxSlider
您可以通过样式表自定义视觉元素的外观。还可以使用事件回调修改视觉元素的行为。
VisualElement
派生出若干定义了额外行为和功能的子类,如控件。UI 工具包提供了各种具有特定行为的内置控件。例如,以下项目是可用的内置控件:
- Buttons(按钮)
- Toggles(开关)
- Text input fields(文本输入字段)
您还可以将视觉元素组合在一起并修改其行为以创建自定义控件。有关内置控件的列表,请参阅控件参考页面。
面板
面板是可视化树的父对象。可视化树必须连接到面板,树中的可视元素才能呈现。所有面板都属于编辑器窗口或运行时 UIDocument。该面板还处理可视化树的焦点控制和事件调度。
视觉树中的每个元素都包含对包含视觉树的面板的直接引用。为了验证 VisualElement
是否已连接到面板,可以测试此元素的 panel
属性。当视觉元素未连接时,测试将返回 null
。
绘制顺序
可视化树中元素的绘制顺序遵循深度优先搜索。子视觉元素显示在父元素的顶部。UI 工具包按同级列表的顺序绘制子元素。抽奖顺序如下:
- 顶级视觉元素。
- 该视觉元素的第一个子元素。
- 后代元素的子元素。
下图显示了上一示例的绘制顺序:
要更改视觉元素绘制顺序,请使用以下函数:
- BringToFront()
- SendToBack()
对于同级视觉元素,请使用以下函数:
- PlaceBehind()
- PlaceInFront()
坐标和位置系统
UI 工具包使用功能强大的布局系统,该系统根据样式属性中的布局参数自动计算各个元素的位置和大小。这是基于Flexbox,一个Web布局模型。有关详细信息,请参阅布局引擎。
UI 工具包有两种坐标:
- 相对:相对于元素计算位置的坐标。布局系统计算元素的位置,然后将坐标添加为偏移量。子元素可以影响父元素的位置和大小,因为布局引擎在计算元素位置时会考虑它们。
- 绝对:相对于父元素的坐标。这样就绕过了自动布局计算,直接设置了元素的位置。同一父级下的子元素对元素的位置没有影响。同样,该元素不会影响同一父级下其他同级元素的位置和大小。
每个视觉元素确定用于计算其位置的坐标系。您可以在元素样式表中配置要使用的坐标系。
下面的代码演示如何通过代码设置一个视觉元素的坐标空间和位置:
var newElement = new VisualElement();
newElement.style.position = Position.Relative;
newElement.style.left = 15;
newElement.style.top = 35;
元素的原点是其左上角。
布局系统为每个元素计算 VisualElement.layout
属性 (type Rect
),其中包括元素的最终位置。这会考虑元素的相对或绝对位置。
layout.position
以点 (point) 表示,相对于其父级的坐标空间。
每个 VisualElement
都有一个变换属性 (ITransform
),您可以使用它为元素的位置和旋转添加额外的局部偏移。偏移量并不在计算的布局属性中表示。默认情况下,transform
是标识。
使用 worldBound
属性检索 VisualElement
的最终窗口空间坐标,同时考虑布局位置和变换。此位置包括窗口标题的高度。
示例
以下代码示例演示了相对定位和绝对定位之间的区别。它使用自动布局系统将一些方框添加到窗口并计算它们的位置。一个方框演示 25 px
的相对偏移,而另一个方框演示 25 px, 25 px
的绝对位置。
要查看此示例运行效果,请执行以下操作:
- Under Assets > Scripts > Editor, create a C# script called
PositioningTestWindow
. - 将下方的代码复制到 C# 脚本。
- 从编辑器工具栏中,选择 Window > UI Toolkit > Positioning Test Window。
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class PositioningTestWindow : EditorWindow
{
[MenuItem("Window/UI Toolkit/Positioning Test Window")]
public static void ShowExample()
{
var wnd = GetWindow<PositioningTestWindow>();
wnd.titleContent = new GUIContent("Positioning Test Window");
}
public void CreateGUI()
{
for (int i = 0; i < 2; i++)
{
var temp = new VisualElement();
temp.style.width = 70;
temp.style.height = 70;
temp.style.marginBottom = 2;
temp.style.backgroundColor = Color.gray;
rootVisualElement.Add(temp);
}
// Relative positioning
var relative = new Label("Relative\nPos\n25, 0");
relative.style.width = 70;
relative.style.height = 70;
relative.style.left = 25;
relative.style.marginBottom = 2;
relative.style.backgroundColor = new Color(0.2165094f, 0, 0.254717f);
rootVisualElement.Add(relative);
for (int i = 0; i < 2; i++)
{
var temp = new VisualElement();
temp.style.width = 70;
temp.style.height = 70;
temp.style.marginBottom = 2;
temp.style.backgroundColor = Color.gray;
rootVisualElement.Add(temp);
}
// Absolute positioning
var absolutePositionElement = new Label("Absolute\nPos\n25, 25");
absolutePositionElement.style.position = Position.Absolute;
absolutePositionElement.style.top = 25;
absolutePositionElement.style.left = 25;
absolutePositionElement.style.width = 70;
absolutePositionElement.style.height = 70;
absolutePositionElement.style.backgroundColor = Color.black;
rootVisualElement.Add(absolutePositionElement);
}
}
坐标系之间的变换
VisualElement.layout.position
和 VisualElement.transform
属性用于定义如何在局部坐标系和父坐标系之间进行转换。
VisualElementExtensions 静态类提供了以下扩展方法在坐标系之间转换点和矩形:
WorldToLocal
将Vector2
或Rect
从Panel
空间转换为元素内的参照。LocalToWorld
将Vector2
或Rect
转换为Panel
空间参照。ChangeCoordinatesTo
将Vector2
或Rect
从一个元素的局部空间转换为另一个元素的局部空间。
由3D建模学习工作室整理翻译,转载请注明出处!