版本: 2021.3+
此示例演示如何将自定义控件绑定到自定义数据类型。
此示例创建了一个自定义数据类型和一个基于三个内置控件的自定义控件。它将自定义控件绑定到自定义数据类型。绘图器在摄氏度和华氏度之间进行转换。
您可以在此 GitHub 存储库 中找到此示例创建的完整文件。
本指南适用于熟悉 Unity 编辑器、UI(用户界面) 允许用户与您的应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
请参阅 术语表 工具包和 C# 脚本的开发人员。在开始之前,请熟悉以下内容
创建一个自定义数据类型 Temperature
,并将其用作序列化属性。
使用任何模板创建一个 Unity 项目。
创建一个名为 bind-custom-data-type
的文件夹以存储所有文件。
创建一个名为 Temperature.cs
的 C# 脚本,并将其内容替换为以下内容
using System;
namespace UIToolkitExamples
{
public enum TemperatureUnit
{
Celsius,
Farenheit
}
[Serializable]
public struct Temperature
{
public double value;
public TemperatureUnit unit;
}
}
创建一个名为 PlanetScript.cs
的 C# 脚本,并将其内容替换为以下内容
using UnityEngine;
namespace UIToolkitExamples
{
public class PlanetScript : MonoBehaviour
{
public Temperature coreTemperature;
}
}
为 Planet
创建一个自定义编辑器和一个自定义 属性绘制器Unity 的一项功能,允许您通过在脚本上使用属性或通过控制特定可序列化类应如何显示来自定义 Inspector 窗口中某些控件的外观 更多信息
请参阅 术语表 用于 Temperature
。
在自定义属性绘制器中,实现一个按钮,通过写入 SerializedProperty
的属性(使用 doubleValue
和 enumValueIndex
)来在华氏度和摄氏度之间转换温度,然后调用 SerializedObject.ApplyModifiedProperties()
。
自定义属性绘制器被视为自定义控件。它是一个以自定义方式运行的内置控件。
创建一个名为 Editor
的文件夹。
在 Editor 文件夹中,创建一个名为 PlanetEditor.cs
的 C# 脚本,并将其内容替换为以下内容
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
namespace UIToolkitExamples
{
[CustomEditor(typeof(PlanetScript))]
public class PlanetEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
return new PropertyField(serializedObject.FindProperty("coreTemperature"));
}
}
}
在 Editor 文件夹中,创建一个名为 TemperatureDrawer.cs
的 C# 脚本,并将其内容替换为以下内容
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace UIToolkitExamples
{
[CustomPropertyDrawer(typeof(Temperature))]
public class TemperatureDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var asset = Resources.Load<VisualTreeAsset>("temperature_drawer");
var drawer = asset.Instantiate(property.propertyPath);
drawer.Q<Label>().text = property.displayName;
// Don't allow conversion when you've selected multiple objects in the Inspector
if (!property.serializedObject.isEditingMultipleObjects)
{
drawer.Q<Button>().RegisterCallback<ClickEvent, SerializedProperty>(Convert, property);
}
return drawer;
}
static void Convert(ClickEvent evt, SerializedProperty property)
{
var valueProperty = property.FindPropertyRelative("value");
var unitProperty = property.FindPropertyRelative("unit");
// F -> C
if (unitProperty.enumValueIndex == (int)TemperatureUnit.Farenheit)
{
valueProperty.doubleValue -= 32;
valueProperty.doubleValue *= 5.0d / 9.0d;
unitProperty.enumValueIndex = (int)TemperatureUnit.Celsius;
}
else // C -> F
{
valueProperty.doubleValue *= 9.0d / 5.0d;
valueProperty.doubleValue += 32;
unitProperty.enumValueIndex = (int)TemperatureUnit.Farenheit;
}
// Important: Because you are bypassing the binding system, you must save the modified SerializedObject
property.serializedObject.ApplyModifiedProperties();
}
}
}
创建一个包含以下内容的 UXML 文件
将这两个字段的 binding-path
设置为 Temperature
属性的 value
和 unit
。
在 Editor 文件夹中,创建一个名为 Resources 的文件夹。
在 Resources 文件夹中,创建一个名为 temperature_drawer.uxml
的 UI 文档,并将其内容替换为以下内容
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<ui:VisualElement class="unity-base-field">
<ui:Label class="unity-base-field__label" />
<ui:VisualElement class="unity-base-field__input" style="flex-direction: row;">
<uie:DoubleField binding-path="value" />
<uie:EnumField binding-path="unit" />
<ui:Button text="Convert" />
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
Temperature
属性也会发生更改。