UXML格式
UXML文件是定义用户界面的逻辑结构的文本文件。UXML文件中使用的格式受HTML(超文本标记语言),XAML(可扩展应用程序标记语言)和XML(可扩展标记语言)的启发。如果您熟悉这些公认的格式,您应该注意到UXML中有很多相似之处。但是,UXML格式包含很小的差异,以提供与Unity一起有效使用的方法。
本节介绍Unity支持的UXML格式,并提供有关编写,加载和定义UXML模板的详细信息。它还包括有关定义新元素以及如何使用UQuery的信息。
UXML可以让技术较低的用户更容易在Unity中构建用户界面。在UXML中,您可以:
- 用XML定义用户界面(UI)的结构。
- 用USS样式表来定义UI布局。
这使得技术开发人员只需执行技术任务,例如导入资产,定义逻辑和处理数据。
定义新元素(扩展UIElement)
UIElement是可扩展的。您可以定义自己的用户界面组件和元素。
在使用UXML文件定义新元素之前,需要从VisualElement或
其子类派生一个新类,然后在此新类中实现适当的功能。您的新类必须实现默认构造函数。
例如,以下代码是派生的新StatusBar
类并实现其默认构造函数:
class StatusBar : VisualElement
{
public StatusBar()
{
m_Status = String.Empty;
}
string m_Status;
public string status { get; set; }
}
为了让UIElements在读取UXML文件时实例化一个新类,您必须为您的类定义一个工厂。除非您的工厂需要做一些特殊的事情,否则您可以从UxmlFactoy<T>派生工厂
。建议您将工厂类放在相应的组件类中。
例如,以下代码演示了如何为StatusBar
定义工厂,它通过派生UxmlFactory<T>
类来定义工厂,工厂名为UxmlFactory
:
class StatusBar : VisualElement
{
public new class UxmlFactory : UxmlFactory<StatusBar> {}
// ...
}
通过定义此工厂,您可以<StatusBar>
在UXML文件中使用该元素。
定义元素的属性
您可以为新类定义UXML特征,并将其工厂设置为使用这些特征。
例如,以下代码演示了如何定义UXML traits类以将status
属性初始化为类的属性StatusBar
。status属性是从XML数据初始化的。
class StatusBar : VisualElement
{
public new class UxmlFactory : UxmlFactory<StatusBar, UxmlTraits> {}
public new class UxmlTraits : VisualElement.UxmlTraits
{
UxmlStringAttributeDescription m_Status = new UxmlStringAttributeDescription { name = "status" };
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get { yield break; }
}
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
((StatusBar)ve).status = m_Status.GetValueFromBag(bag, cc);
}
}
// ...
}
UxmlTraits
有两个目的:
-
工厂使用它来初始化新创建的对象。
-
它通过schema的生成过程进行分析,以获取有关元素的信息。此信息将被转换为XML schema 指令。
上面的示例代码执行了以下操作:
- 声明
m_Status的变量
定义了一个名为status
的XML属性。 - 在
uxmlChildElementsDescription
返回空IEnumerable
表明StatusBar
元素没有子元素。 Init()
方法从XML解析器的属性包中读取status
属性,并将StatusBar.status
属性设置为此值。- 通过将
UxmlTraits
类放在StatusBar
类中允许该Init()
方法访问StatusBar的
私有成员。 - 新
UxmlTraits
类继承自基类UxmlTraits
,因此它可以共享基类的属性。 Init()
调用base.Init()
初始化基类属性。
上面的代码示例使用UxmlStringAttributeDescription
类声明了一个字符串属性。UIElements支持以下类型的属性,每个属性都将C#类型链接到XML类型:
属性 | 属性值 |
---|---|
UxmlStringAttributeDescription | 一个字符串 |
UxmlFloatAttributeDescription | C#float 类型范围内的单精度浮点值。 |
UxmlDoubleAttributeDescription | C#double 类型范围内的双精度浮点值。 |
UxmlIntAttributeDescription | C#int 类型范围内的整数值。 |
UxmlLongAttributeDescription | C#long 类型范围内的长整数值。 |
UxmlBoolAttributeDescription | true 要么 false |
UxmlColorAttributeDescription | 表示颜色的字符串(#FFFFFF ) |
UxmlEnumAttributeDescription<T> | 表示该Enum 类型的值之一的字符串T 。 |
在上面的代码示例中,uxmlChildElementsDescription
返回一个空IEnumerable
,表示该StatusBar
元素不接受子元素。
要让元素接受某种类型的子元素,必须重写该uxmlChildElementsDescription
属性。例如,为了让StatusBar
接受任何类型的子元素,uxmlChildElementsDescription
需要按如下方式指定属性:
public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
{
get
{
yield return new UxmlChildElementDescription(typeof(VisualElement));
}
}
定义名称空间前缀
在C#中定义新元素后,即可开始在UXML文件中使用该元素。如果在新命名空间中定义了新元素,则应为命名空间定义前缀。命名空间前缀被声明为根<UXML>
元素的属性,并在元素作用域时替换为完整的命名空间名称。
要定义命名空间前缀,需要为要定义的每个命名空间前缀向程序集添加一个UxmlNamespacePrefix
属性。
[assembly: UxmlNamespacePrefix("My.First.Namespace", "first")]
[assembly: UxmlNamespacePrefix("My.Second.Namespace", "second")]
这可以在程序集的根级别(任何命名空间之外)的任何C#文件中完成。
schema 生成系统将执行以下操作:
- 检查这些属性并使用它们生成schema 。
- 在新创建的UXML文件中,添加命名空间前缀定义作为
<UXML>元素的
属性 - 为命名空间包含schema文件位置,存放在它的
xsi:schemaLocation
属性中。
当你需要更新项目中的UXML的schema时,选择菜单Assets> Update UIElements Schema以确保文本编辑器识别新元素。
通过在 Project/Assets/Editor
文件夹中选择 Create > UIElements Editor Window ,可以在新创建的UXML中生成已定义的命名空间前缀。
高级用法
自定义UXML名称
您可以通过覆盖其IUxmlFactory.uxmlName
和IUXmlFactory.uxmlQualifiedName
属性来定制UXML名称。确保uxmlName
在命名空间中是唯一的,而uxmlQualifiedName
在项目中是唯一的。
如果两个名称都不唯一,则在尝试加载程序集时会引发异常。
以下代码示例演示如何覆盖和自定义UXML名称:
public class FactoryWithCustomName : UxmlFactory<..., ...>
{
public override string uxmlName
{
get { return "UniqueName"; }
}
public override string uxmlQualifiedName
{
get { return uxmlNamespace + "." + uxmlName; }
}
}
为元素选择工厂
默认情况下,IUxmlFactory
实例化一个元素并使用元素的名称来选择元素。
您可以通过覆盖IUXmlFactory.AcceptsAttributeBag
来在选择过程考虑元素的属性值。然后,工厂将检查元素属性,以确定它是否可以为UXML元素实例化对象。
例如,如果您的VisualElement
类是泛型类,那么这会很有用。在这种情况下,类的专有工厂可以检查XML的type
属性的值。根据具体值来决定接受或拒绝实例化。请参阅PropertyControl<T>
的实现示例。
在多个工厂都可以实例化同一类元素的情况下,将会选择第一个注册的工厂。
覆盖基类属性的默认值
您可以通过在派生UxmlTraits
类中设置defaultValue
来更改基类中声明的属性默认值。
例如,以下代码显示了如何更改默认值m_TabIndex
:
class MyElementTraits : VisualElement.UxmlTraits
{
public MyElementTraits()
{
m_TabIndex.defaultValue = 0;
}
}
接受任何属性
默认情况下,生成的XML schema中声明元素可以具有任何属性。
除了在UxmlTraits
类中声明的属性之外,其它属性都不受限制。这与XML验证器形成对比,后者检查声明的属性的值是否与其声明匹配。
附加属性包含在IUxmlAttributes
包中,被传递给IUxmlFactory.AcceptsAttributBag()
和IUxmlFactory.Init()
函数。是否使用这些附加属性取决于工厂实现。默认行为是放弃附加属性。
这意味着这些附加属性未附加到实例化的VisualElement
,并且这些附加属性无法通过UQuery
来查询获得。
定义新元素时,可以通过在UxmlTraits
构造函数中将UxmlTraits.canHaveAnyAttribute
属性设置为false
,将接受的属性限制为显式声明过的属性。
使用Schema定义
Schema 定义文件指定每个UXML元素可以包含的属性和子元素。应使用Schema 定义文件作为你正确编写UXML文档和验证UXML文档的指南。
在UXML 模板文件中,<UXML>
根元素的xsi:noNamespaceSchemaLocation
和xsi:schemaLocation
属性指定的Schema 定义文件的位置。
选择Assets > Create > UIElements Editor Window,将会自动更新Schema定义文件,它会使用项目的VisualElement
子类中的最新信息。要强制更新UXML模式文件,请选择“ Assets > Update UIElements Schema”。
注意:某些文本编辑器无法识别该xsi:noNamespaceSchemaLocation
属性。如果文本编辑器找不到架构定义文件,则还应指定该xsi:schemaLocation
属性。