Unity 2019.1的UIElements功能介绍

UIElements是Unity全新的保留模式UI框架,面向Unity 2019.1作为公开API发布。现在UIElements是一款可以轻松扩展Unity编辑器的工具,未来版本将加入游戏内支持和可视化制作功能。

你可以下载UIElements示例项目进行学习:

https://github.com/Unity-Technologies/UIElementsUniteLATurretDemo

UIElements介绍

过去,在Unity中构建自定义编辑器窗口和检视窗口意味着要使用即时模式API:IMGUI。

IMGUI可以帮助你轻松的构建用户界面,但是在构建较复杂的应用程序时会很难扩展。系统也很难优化渲染过程,因为用户可以随时在某一帧内大幅修改UI结构。

IMGUI的所有UI都通过C#代码声明,这意味着未来可视化制作UI的工具都会生成C#代码,这种做法很复杂。

UIElements作为保留模式API,它的核心思想是:用户构建出自己的UI对象层级,然后让系统进行渲染。通过这种方式,该系统可以优化绘制的内容和时间,从而实现更好的整体性能。

这种范例也允许用户把层级和样式从功能中分离,从而更好地分开关注点,为艺术家和程序员提供更易于理解的UI制作过程。

保留模式

UIElements的基本构造部分是VisualElement类,所有元素都是VisualElement或从中继承。独立的VisualElement可以互相嵌套,以形成UI层级。布局,样式和其它系统会遍历该层级,以便正确地渲染UI到屏幕上。

在编辑器中,每个EditorWindow都有一个rootVisualElement属性,该属性表示层级的顶部VisualElement。Element元素需要作为子对象添加到根对象上,从而让系统知道元素的信息,并进行绘制。

using UnityEditor;
using UnityEngine.UIElements;
public class ExampleWindow : EditorWindow
{
   public void OnEnable()
   {
       var root = this.rootVisualElement;
       IntSlider slider = new IntSlider();
       root.Add(slider); //  添加滑块为根对象的子对象                   
   }
}


只要元素处于层级之中,它会继续绘制,更新和消耗用户事件,而无需开发人员的输入。这就是保留模式和即时模式最大的不同之处,开发人员只需声明应该发生的事情和发生时间,不需要管理帧和帧之间的渲染。

为了停止绘制某个元素,例如这里的滑块,开发人员既可以通过样式变更,使它暂时无法看到,也可以把它从层级中永久移除。

// 轻松而动态地隐藏和显示元素
slider.style.display = Display.None;
// 该元素的工作已经完成,可以移除它了
slider.RemoveFromHierarchy();

保留模式也可以使用文档模型,让开发者分离层级(使用UXML)和样式(USS)声明为单独的资源。在C#代码中,你可以使用内置查询系统和事件系统,仅专注于绑定声明的UI和功能及数据。

通过为层级和样式使用分离的资源,可以可视化制作UI,可让所有用户在Unity中轻松调整、制作和设计UI。

可重用模板UXML

你可以完全使用C#代码组合元素层级,但和样式一样,大多数层级不会在UI的生命周期内有太大变化。因此建议模块化处理UI,定义层级为基于XML的独立资源,即UXML。

<UXML xmlns="UnityEngine.UIElements">
   <VisualElement name="the-container">
       <Label />
       <SliderInt low-value="0" high-value="100" />
   </VisualElement>
</UXML>


标签名称对应着C#类型,完全支持继承自VisualElement的用户定义类型。属性会在创建时在新元素上设置,嵌套的标签会成为父标签的子标签。

你可以像其它Unity资源一样加载.uxml资源,在过程中构造VisualTreeAsset对象,然后根据需要在任意元素下实例化或克隆VisualTreeAsset。

var uxml =
    AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ExampleUI.uxml");
uxml.CloneTree(root); //在uxml中创建标签为根部分的子部分

下面将介绍如何使用查询系统通过UXML获取刚创建的元素。

共享样式USS

通过C#的属性可以直接在VisualElements上设置样式。虽然大部分样式会静态定义的,但它也可以在C#代码中分离描述和UI逻辑。

UIElements使用Unity专用的StyleSheet资源,称为USS,它使用CSS标准的子集。你可以使用和CSS代码相同的选择器,以识别哪些元素应该得到什么样式,样式本身是键值对。

/* 按照样式类 */
.standard-label {
    padding: 6px;
}
/* 按照元素名称 */
#the-label {
    font-size: 60px;
}
/* 按照C#类型 */
Label {
    color: rgb(68, 255, 93);
}


你可以像其它Unity资源一样加载.uss资源,在过程中构造StyleSheet对象,然后指定它到所需的元素,它会自动应用其中的样式到该元素及其子元素上。

var uss = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/ExampleUI.uss");
root.styleSheets.Add(uss);

虽然样式可以根据名称属性或C#类型来应用,但为了更好的样式重用效果,你可以给元素指定一个或多个样式类,根据这些类在USS资源匹配样式,你可以把这些样式视为标签。

<!-- Assign a style class in UXML: -->
<Label />
// 在C#指定样式类
var label = new Label();
label.AddToClassList("blue-label");

你可以添加多个StyleSheets到相同元素,使用多个规则来匹配相同的元素。使用USS来设置复杂的重写规则,同时尽可能重复使用样式。

这样对共享样式进行迭代变成了很简单的事情,因为我们不必等待C#代码进行重新编译。StyleSheet(USS)资源的改动会在文件保存时自动应用到编辑器。

UQuery

UIElements中的查询系统叫UQuery,它和Web上的jQuery类似,允许你使用名称属性,当前指定的样式类列表和C#类型的组合来查找层级中的元素。

// 通过样式类和类型
var label = root.Q<Label>(className: "blue-label");
// 通过名称(它会返回VisualElement)
var container = root.Q("the-container");

你还可以创建Query对象以实现优化的重用效果,此时需要对动态层级多次运行查询过程。

// 构建一次查询
UQueryBuilder<SliderInt> query = root.Query<SliderInt>(classes: "blue-slider");
// 多次运行以获取更新结果
query.ForEach(slider => Debug.Log(slider.name));

事件

UIElements提供了一个事件系统。事件通常会发送到特定元素,然后在UI树的上下传播,直到使用完所有事件,但传播行为是可以定制的。

MouseMoveEvent等基本事件会由系统发送,你可以进行注册以接收事件,也可以定义和发送自定义用户事件。Event事件是了解UI中的状态何时变化或用户何时执行操作的主要方法。

下面的示例会检测用户何时改动滑块数值,然后在标签元素显示新的数值。

var label = new Label();
var slider = new SliderInt();
slider.RegisterCallback< ChangeEvent<int>>(evt =>
{
   display.text = evt.newValue.ToString();
});


UIElements Debugger

如果UI出现问题,或是如果没有看到应该出现在屏幕的元素,你可以使用UIElements Debugger,该工具类似Chrome和Firefox里的网页调试工具。

使用UIElements Debugger调试UI的元素,可以启用Pick功能,把鼠标移动到元素上,或是右键单击元素并选择Inspect。UIElements Debugger会在左侧面板显示当前窗口的完整实时层级,在右侧面板显示样式检视窗口。

在样式检视窗口中,你可以查看什么样式指定到某个元素上,以及每个样式值来自什么地方,即在哪个StyleSheet资源和哪个选取器内。

最后,你可以实时添加和编辑样式值,在UI查看它们的效果。


其它功能

Bindings绑定

许多控制功能可以绑定到SerializedObjects,以链接UI和资源数据。任何实现IBindableinterface的元素,例如:所有内置字段都可以接收SerializedProperty的字符串绑定路径。然后你可以把元素层级通过 Bind()绑定到SerializedObjects。

IMGUIContainer

如果有许多使用IMGUI编写的编辑器UI,你可以使用特别的IMGUIContainer元素在UIElements UI中作为另一元素嵌入IMGUI UI。IMGUIContainer会获取用作OnGUI( )循环的回调,和正常情况一样从外部接收所有事件。

Scheduler调度工具

UIElements提供了一个简单的内置调度工具,你可以使用调度工具按一定时间延迟回调,然后以设定的间隔重复执行回调。

未来展望

我们正在开发UIElements对游戏内UI 的支持。此外,我们计划为UIElements提供可视化工作流程,让用户可以通过少量C#代码,甚至不使用C#代码来设计和构造可用的UI。

与此同时,Unity上越来越多的部分将使用UIElements构建,包括检视窗口,使用专用编辑器窗口的新工具和新工具栏。

我们会继续维护和改进IMGUI和UGUI,我们目前没有弃用它们的计划。尽管如此,UIElements将成为得到最多支持的推荐方法,用于在Unity构造UI,UIElements从Unity 2019.1开始在编辑器内使用。

更多Unity最新功能分享与技术讨论,尽在Unity Connect平台(Connect.unity.com)。下载Unity Connect APP,请点击此处

本文转自:微信号 - Unity官方平台(Unity-GreaterChina),转载此文目的在于传递更多信息,版权归原作者所有。

最新文章