Unity 可扩展标记语言 (UXML) 文件是定义用户界面逻辑结构的文本文件。UXML 格式受到 HTML、XAML 和 XML 的启发。如果您以前使用过这些格式,会发现与 UXML 的相似之处。但是,UXML 格式包含一些小差异,旨在与 Unity 高效融合。
本节介绍 Unity 支持的 UXML 格式,并提供有关编写、加载和定义 UXML 模板的详细信息。还包含有关定义新元素以及如何使用 UQuery 的信息。
UXML 使技术水平较低的用户更容易在 Unity 中构建用户界面。在 UXML 中可以:
因此,开发者可以将精力集中于执行一些技术性工作,例如导入资源、定义逻辑和处理数据。
使用 UI 工具包,您可以定义自己的用户界面组件和元素。
在使用 UXML 文件来定义新元素之前,必须从 VisualElement
或其子类之一派生一个新类,然后在此新类中实现相应功能。新类必须实现默认构造函数。
例如,以下代码派生新的 StatusBar
类并实现其默认构造函数:
class StatusBar : VisualElement
{
public StatusBar()
{
m_Status = String.Empty;
}
string m_Status;
public string status { get; set; }
}
In order for UI Toolkit to instantiate a new class when reading a UXML file, you must define a factory for your class. Unless your factory needs to do something special, you can derive the factory from UxmlFactory<T>
. It’s recommended that you put the factory class within your component class.
例如,以下代码演示了如何通过从 UxmlFactory<T>
派生 StatusBar
类的工厂来为该类定义工厂。该工厂名为 UxmlFactory
:
class StatusBar : VisualElement
{
public new class UxmlFactory : UxmlFactory<StatusBar> {}
// ...
}
定义该工厂后,就可以在 UXML 文件中使用 <StatusBar>
元素。
可为新类定义 UXML 特征,并将其工厂设置为使用这些特征。
例如,以下代码演示了如何定义 UXML 特征类,从而将 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
有两个作用:
以上代码示例执行以下操作:
m_Status
的声明定义一个名为 status
的 XML 属性。uxmlChildElementsDescription
返回空的 IEnumerable
(表明 StatusBar
元素没有子项)。Init()
成员从 XML 解析器读取属性包中的 status
属性值,并将 StatusBar.status
属性设置为此值。UxmlTraits
类置于 StatusBar
类中,让 Init()
方法可以访问 StatusBar
的私有成员。UxmlTraits
类继承自基类 UxmlTraits
,因此其共享基类的属性。Init()
调用 base.Init()
来初始化基类属性。以上代码示例使用 UxmlStringAttributeDescription
类声明了一个字符串属性。UI 工具包支持以下类型的属性,每个属性都将 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# 文件的根级别(在任何命名空间之外)完成。
架构生成系统会执行以下操作:
<UXML>
元素的属性。xsi:schemaLocation
属性中。应该更新项目的 UXML 架构。请选择 Assets > Update UXML Schema 以确保文本编辑器识别新元素。
通过在 Project/Assets/Editor
文件夹中选择 Create > UI Toolkit > Editor Window,可以在新创建的 UXML 中使用定义的前缀。
若要自定义 UXML 名称,可覆盖其 IUxmlFactory.uxmlName
和 IUXmlFactory.uxmlQualifiedName
属性。确保 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 架构会声明元素可以具有任何属性。
属性值(在 UxmlTraits
类中声明的属性除外)不受限制。这一点与 XML 验证器相反,后者会检查已声明属性的值是否与其声明匹配。
其他属性包含在传递到 IUxmlFactory.AcceptsAttributBag()
和 IUxmlFactory.Init()
函数的 IUxmlAttributes
包中。是否使用这些附加属性取决于工厂的实现。默认行为是丢弃附加属性。
这意味着这些附加属性不会附加到实例化的 VisualElement
,并且不能使用 UQuery
来查询这些属性。
定义新元素时,可以通过在 UxmlTraits
构造函数中将 UxmlTraits.canHaveAnyAttribute
属性设置为 false
,将接受的属性限制为显式声明的属性。
架构定义文件用于指定属性以及每个 UXML 元素可以包含的子元素。请将架构定义文件用作编写正确文档和验证文档的指南。
在 UXML 模板文件中,<UXML>
根元素的 xsi:noNamespaceSchemaLocation
和 xsi:schemaLocation
属性指定了架构定义文件所在位置。
选择 Assets > Create > UI Toolkit > Editor Window,即可使用从项目所用的 VisualElement
子类中收集的最新信息来自动更新架构定义。要强制更新 UXML 架构文件,请选择 Assets > Update UXML Schema。
注意:某些文本编辑器无法识别 xsi:noNamespaceSchemaLocation
属性。如果文本编辑器找不到架构定义文件,您还应指定 xsi:schemaLocation
属性。