声明字段或属性与嵌套的 UXML 对象相关联。
您可以利用 UxmlObjectReferenceAttribute 指示属性或字段链接到一个或多个 UXML 对象。通过向类添加 UxmlObjectAttribute 属性,您可以声明一个 UXML 对象。您可以使用这些 UXML 对象将复杂数据与字段关联,超越单个 UxmlAttributeAttribute 的功能。字段类型必须是 UXML 对象或接口。当使用接口时,只有 UXML 对象类型对 UXML 序列化有效。
以下示例显示了 UxmlObjectReferenceAttribute 的常见用例。它使用该属性将 UXML 对象列表与字段或属性关联
using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements;
[UxmlObject] public partial class Option { [UxmlAttribute] public string name { get; set; }
[UxmlAttribute] public bool bold { get; set; }
[UxmlAttribute] public Color color; }
[UxmlElement] public partial class MyColoredListField : VisualElement { private List<Option> m_Options; private PopupField<Option> m_PopupField;
[UxmlObjectReference("options")] public List<Option> options { get => m_Options; set { m_Options = value; m_PopupField.choices = m_Options; } }
public MyColoredListField() { m_PopupField = new PopupField<Option>(); Add(m_PopupField);
if (options != null) m_PopupField.choices = options;
m_PopupField.formatSelectedValueCallback = FormatItem; m_PopupField.formatListItemCallback = FormatItem; }
static string FormatItem(Option option) { if (option == null) return "";
var coloredString = $"<color=#{ColorUtility.ToHtmlStringRGB(option.color)}>{option.name}</color>";
if (option.bold) return $"<b>{coloredString}</b>"; return coloredString; } }
示例 UXML
<ui:UXML xmlns:ui="UnityEngine.UIElements"> <MyColoredListField> <options> <Option name="Red" color="#FF0000FF" bold="true" /> <Option name="Green" color="#00FF00FF" /> <Option name="Blue" color="#0000FFFF" /> </options> </MyColoredListField> </ui:UXML>
您可以使用基本类型并将派生类型合并为 UXML 对象。以下示例自定义按钮以在单击时表现出不同的行为,例如显示标签或播放声音效果。
using UnityEngine; using UnityEngine.UIElements;
[UxmlObject] public abstract partial class ButtonBehaviour { [UxmlAttribute] public string name { get; set; }
public abstract void OnClicked(Button button); }
[UxmlObject] public partial class CreateLabel : ButtonBehaviour { [UxmlAttribute] public string text { get; set; } = "I was clicked!";
public override void OnClicked(Button button) { var label = new Label(text); button.parent.Add(label); } }
[UxmlObject] public partial class PlaySound : ButtonBehaviour { [UxmlAttribute] public AudioClip sound { get; set; }
public override void OnClicked(Button button) { AudioSource.PlayClipAtPoint(sound, Vector3.zero); } }
[UxmlElement] public partial class ButtonWithClickBehaviourExample : Button { [UxmlObjectReference("clicked")] public ButtonBehaviour clickedBehaviour { get; set; }
public ButtonWithClickBehaviourExample() { clicked += OnClick; }
void OnClick() { clickedBehaviour?.OnClicked(this); } }
示例 UXML
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False"> <ButtonWithClickBehaviourExample text="Play Sound"> <clicked> <PlaySound sound="project://database/Assets/ClickedSound.wav" /> </clicked> </ButtonWithClickBehaviourExample> <ButtonWithClickBehaviourExample text="Show Label"> <clicked> <CreateLabel text="I was clicked!" /> </clicked> </ButtonWithClickBehaviourExample> </ui:UXML>
您还可以将接口与实现它的 UXML 对象一起使用。
using System.Collections.Generic; using UnityEngine.UIElements;
public interface IMyUxmlObjectInterface { string name { get; set; } }
[UxmlObject] public partial class MyUxmlObject : IMyUxmlObjectInterface { [UxmlAttribute] public string name { get; set; } }
[UxmlElement] public partial class MyUxmlObjectElement : VisualElement { [UxmlObjectReference("item")] public IMyUxmlObjectInterface item { get; set; }
[UxmlObjectReference("item-list")] public List<IMyUxmlObjectInterface> itemList { get; set; } }
以下示例创建了多个具有自定义属性绘制器的 UxmlObjects 类型。它使用 UxmlObjects 来描述学校、老师和学生
using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements;
/// <summary> /// The classes that a student can take. /// </summary> public enum Class { Maths, MathsAdvanced, Science, ScienceAdvanced, Psychology, Sociology, Economics, English, French, History, }
/// <summary> /// The base class contains the common properties for both students and teachers. /// </summary> [UxmlObject] public abstract partial class Person { [UxmlAttribute] public int Id { get; set; }
[UxmlAttribute] public string Name { get; set; } }
/// <summary> /// A student has a list of classes and a photo. /// </summary> [UxmlObject] public partial class Student : Person { [UxmlAttribute] public List<Class> Classes { get; set; }
[UxmlAttribute] public Texture2D Photo { get; set; } }
/// <summary> /// A teacher has a list of classes taught. /// </summary> [UxmlObject] public partial class Teacher : Person { [UxmlAttribute] public List<Class> ClassesTaught { get; set; } }
/// <summary> /// A school has a list of people which includes both students and teachers. /// </summary> [UxmlObject] public partial class School { [UxmlAttribute] public string Name { get; set; }
[UxmlAttribute] public int NextAvailableId;
[UxmlObjectReference("people")] public List<Person> People { get; set; } }
/// <summary> /// A school district has a list of schools. /// </summary> [UxmlElement] public partial class SchoolDistrict : VisualElement { [UxmlObjectReference("schools")] public List<School> Schools { get; set; } }
您可以使用自定义属性绘制器在 Inspector 中显示 UXML 对象。属性绘制器必须用于 UxmlObject 的 UxmlSerializedData 类型。例如,要为 UxmlObject Student 创建属性绘制器,绘制器必须用于 Studen.UxmlSerializedData 类型。
using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements;
// Note: The custom property drawer must be for the serialized data type. [CustomPropertyDrawer(typeof(School.UxmlSerializedData))] public class SchoolPropertyDrawer : PropertyDrawer { SerializedProperty m_People; SerializedProperty m_NextAvailableId; ListView m_ListView;
int GetNextId() { var id = m_NextAvailableId.intValue; if (id == 0) id++;
m_NextAvailableId.intValue = id + 1; return id; }
public override VisualElement CreatePropertyGUI(SerializedProperty property) { var root = new VisualElement();
m_People = property.FindPropertyRelative("People"); m_NextAvailableId = property.FindPropertyRelative("NextAvailableId");
var name = new PropertyField(); name.BindProperty(property.FindPropertyRelative("Name")); root.Add(name);
m_ListView = new ListView { showAddRemoveFooter = true, showBorder = true, showBoundCollectionSize = false, showAlternatingRowBackgrounds = AlternatingRowBackground.All, overridingAddButtonBehavior = OnAddItem, reorderable = true, reorderMode = ListViewReorderMode.Animated, virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight, bindingPath = m_People.propertyPath, };
root.Add(m_ListView);
return root; }
void OnAddItem(BaseListView baseListView, Button button) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Student"), false, () => AddItem<Student>()); menu.AddItem(new GUIContent("Teacher"), false, () => AddItem<Teacher>()); menu.DropDown(button.worldBound); }
void AddItem<T>() where T : new() { m_People.InsertArrayElementAtIndex(m_People.arraySize); var person = m_People.GetArrayElementAtIndex(m_People.arraySize - 1); person.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(T)); person.FindPropertyRelative("Id").intValue = GetNextId(); m_People.serializedObject.ApplyModifiedProperties(); m_ListView.RefreshItem(m_People.arraySize - 1); } }
[CustomPropertyDrawer(typeof(Student.UxmlSerializedData))] public class StudentPropertyDrawer : PropertyDrawer { public override VisualElement CreatePropertyGUI(SerializedProperty property) { var id = property.FindPropertyRelative("Id").intValue; var photo = property.FindPropertyRelative("Photo").objectReferenceValue as Texture2D;
var root = new VisualElement { style = { backgroundColor = new Color(0, 0.2f, 0, 0.25f) } }; root.Add(new Label($"Student({id})") { style = { unityTextAlign = TextAnchor.MiddleCenter } }); var image = new Image { image = photo, style = { height = 100, width = 100 } }; root.Add(image);
var name = new PropertyField(); name.BindProperty(property.FindPropertyRelative("Name")); root.Add(name);
var photoField = new PropertyField(); photoField.BindProperty(property.FindPropertyRelative("Photo")); photoField.RegisterValueChangeCallback(evt => { image.image = property.FindPropertyRelative("Photo").objectReferenceValue as Texture2D; }); root.Add(photoField);
var course = new PropertyField(); course.BindProperty(property.FindPropertyRelative("Classes")); root.Add(course);
return root; } }
[CustomPropertyDrawer(typeof(Teacher.UxmlSerializedData))] public class TeacherPropertyDrawer : StudentPropertyDrawer { public override VisualElement CreatePropertyGUI(SerializedProperty property) { var id = property.FindPropertyRelative("Id").intValue; var root = new VisualElement { style = { backgroundColor = new Color(0, 0, 0.2f, 0.25f) } }; root.Add(new Label($"Teacher({id})") { style = {unityTextAlign = TextAnchor.MiddleCenter }});
var name = new PropertyField(); name.BindProperty(property.FindPropertyRelative("Name")); root.Add(name);
var classField = new PropertyField(); classField.BindProperty(property.FindPropertyRelative("ClassesTaught")); root.Add(classField);
return root; } }
示例 UXML
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False"> <SchoolDistrict> <schools> <School name="Herrington High School" next-available-id="6"> <people> <Teacher id="1" classes-taught="Science" name="Elizabeth Burke" /> <Teacher id="2" classes-taught="Maths" name="Coach Willis" /> <Student id="3" classes="Maths" name="Casey Connor" /> <Student id="4" classes="Maths,English,French,History,Sociology" name="Delilah Profitt" /> <Student id="5" classes="Maths,MathsAdvanced,Science,ScienceAdvanced" name=" Marybeth Louise Hutchinson" /> </people> </School> <School name="Shermer High School" next-available-id="9"> <people> <Teacher id="3" classes-taught="English" name="Ed Rooney" /> <Teacher id="4" name="Mr. Lorensax" classes-taught="Economics" /> <Teacher id="5" classes-taught="English" name="Mr. Knowlan" /> <Teacher id="6" classes-taught="History" name="Mr. Rickets" /> <Student id="1" classes="Maths,Science,English" name="Ferris Bueller" /> <Student id="7" classes="Maths,MathsAdvanced,Science,ScienceAdvanced,French" name="Cameron Frye" /> <Student id="8" classes="Sociology,Economics,Phycology" name="Sloan Peterson" /> </people> </School> <School name="Sunnydale High School" next-available-id="6"> <people> <Teacher id="1" classes-taught="Science,ScienceAdvanced" name="Grace Newman" /> <Teacher id="2" classes-taught="Science" name="Dr. Gregory" /> <Student id="3" classes="Maths" name=" James Stanley" photo="project://database/Assets/james-class-photo.jpg" /> <Student id="4" classes="Maths,English,French,History,Sociology" name="Buffy Summers" photo="project://database/Assets/buffy-class-photo.jpg" /> <Student id="5" classes="Maths,MathsAdvanced,Science,ScienceAdvanced" name="Willow Rosenberg" photo="project://database/Assets/willow-class-photo.jpg" /> </people> </School> </schools> </SchoolDistrict> </ui:UXML>
name | UXML 对象序列化到的嵌套 UXML 元素的名称。注意:空值或空字符串会导致对象序列化到根节点。 |
types | 在 UI Builder 中,当将 UXML 对象添加到具有多个派生类型的字段时,会显示一个下拉列表,其中包含可添加到字段的可用类型的选择。默认情况下,此列表包含从 UXML 对象类型继承的所有类型。您可以使用参数指定要显示的已接受类型的列表,而不是显示所有可用类型 |
UxmlObjectReferenceAttribute | 声明字段或属性与嵌套的 UXML 对象相关联。 |