本系列文章介绍UIElement知识点,欢迎访问😉

本系列文章使用的Unity版本为2019.3.7f1

前言

首先我们来理解一下为什么官方提供UQuery这一套东西。
UQuery是一组扩展方法,允许您在复杂的层次结构中选择单独的或集合的visualelement。为了从任何UIElements元素可视树中检索也就是找到业务逻辑中想要的元素,提供的UQuery这一组拓展方法。官方解释说UQuery基于JQuery,那么从JQuery入手来理解一下原理。学过前端的同学应该都清楚JQuery的用法(我没学过,这里现学现用一下🤣🤣🤣,如有错误,请见谅)。

什么是JQuery?

JQuery是一个轻量级的JavaScript函数库,包含以下功能:

  • HTML元素选取
  • HTML元素操作
  • CSS操作
  • HTML事件函数
  • JavaScript特效和动画
  • HTML DOM遍历和修改
  • AJAX
  • Utilities

粗略看来,JQuery可以检索到HTML中的元素并进行操作,这跟UQuery提供的功能是一致的,至于JQuery提供的别的功能,UQuery以后的发展目前不得而知。

为什么需要提供UQuery?

UIElement的结构是通过UXML+USS的形式完成一个元素可视树(也就是UI)的绘制,这跟传统的Prefab工作模式有很大的区别。UIElement制作出来的UI以UXML+USS两类文件存在于工程中,并不存在Prefab,也不能在Hierarchy下看到UI的层级,可以通过UIElements Debugger(Window->Analysns->UIElements Debugger)或者后面会讲到的UI Builder进行查看。既然不存在Prefab,传统的Prefab+MonoBehavior做法也就不再适用了,Prefab+Mono Find Child就没啥说的了,一样。那以前的Prefab+非Mono Find Child的模式呢? 其实我的理解呢,Find Child的模式,就是在一个UI里检索业务逻辑需要的元素,进而进行业务逻辑的开发,这就跟UQuery一样了,都是要在UI中检索元素,只是两者的检索方式不一样罢了。

使用UQuery的好处?

以前通过Find Child检索元素的方式,弊端在于代码中检索元素时使用的Path被层级位置所限制,这样无法做到UI Prefab制作工作与业务逻辑脚本开发工作的完全分离。而使用Prefab+Mono脚本(非Find,直接序列化绑定)的方式,也有弊端,手动拖费时费力(因此网上目前也有开源的自动绑定UI元素的开源库)。使用UIElement后,通过UQuery这一套接口,只需要UI制作人员与程序制定好交互UI元素的命名、UI界面上各区域的划分,更好的做到工作内容分离。至于Runtime下如何打开一个UI,以及打开后的事件绑定等后续业务逻辑开发工作,后续更新Runtime Demo进行介绍。

UQueryExtensions

UQueryExtensions.Q

根据检索条件,查找符合条件的第一个元素,Query<T>.Build().First()方法的简写。

Function

1
2
public static T Q(this UIElements.VisualElement e, string name, string className);
public static T Q(this UIElements.VisualElement e, string name, params string[] classes);

Parameters

  • UIElements.VisualElement e:在该元素上使用条件检索,理解为使用该检索条件的root,不一定是整个UI的Root
  • string name:限制检索元素的name
  • string className:限制检索元素的class,并不是面向对象的class
  • string[] classes:限制检索元素的class(多个),并不是面向对象的class

Return

返回符合检索条件的第一个元素,如果找不到则为null。

UQueryExtensions.Q<T>

UQueryExtensions.Q的泛型接口

UQueryExtensions.Query

返回一个UQueryBuilder<VisualElement>,UQueryBuilder类里包括一些Style选择器、RuleMatcher匹配规则,然后通过First、Last、ToList、AtIndex等接口根据检索规则查找符合规则的元素并返回,ForEach接口主要是对符合匹配规则的检索出来的元素都执行一遍传入的Function。

UQueryExtensions.Query<T>

UQueryExtensions.Query的泛型接口

举例

新建一个UQueryDemo.uxml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<engine:UXML
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:engine="UnityEngine.UIElements"
xmlns:editor="UnityEditor.UIElements"
xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
>

<engine:Button text="Button1" name="Button1" />
<engine:Button text="Button2" name="Button2" />
<engine:Box>
<engine:Label text="This is Label in Box" />
<engine:Button text="Button3" name="Button3" />
</engine:Box>
</engine:UXML>

C# 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var queryDemo = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UQueryDemo.uxml");
root.Add(queryDemo.CloneTree());
//检索到命名为Button1的按钮,添加点击事件
root.Q<Button>("Button1").clickable.clicked += delegate
{
Debug.LogError("Click1");
};
//检索到类型为Button的第一个元素,添加点击事件
root.Query<Button>().First().clickable.clicked += delegate
{
Debug.LogError("Click1");
};
//检索所有Button类型,使用ForEach遍历检索出的Button,给这些Button均添加点击事件
//尽管Button3放在了一个Box元素里,依然被下面的的代码检索到了。
root.Query<Button>().ForEach(delegate(Button button)
{
button.clickable.clicked += delegate
{
Debug.LogError(button.text);
};
}
);

更多的UIElement知识点文章,还在进行中,如有相关内容需要介绍的,可以在下方留言,抽空更新文章~

以上知识分享,如有错误,欢迎指出,共同学习,共同进步,欢迎留言评论!