Version: Unity 6.0 (6000.0)
语言 : 中文
绑定自定义控件
支持编辑器 UI

将自定义控件绑定到自定义数据类型

版本:2021.3+

此示例演示了如何将自定义控件绑定到自定义数据类型。

示例概述

此示例基于三个内置控件创建了自定义数据类型和自定义控件。它将自定义控件绑定到自定义数据类型。绘制器 (drawer) 可在摄氏度和华氏度之间转换。

您可以在此 GitHub 代码仓库中找到此示例创建的完整文件。

先决条件

本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发者。在开始之前,请熟悉以下内容:

创建自定义数据类型

创建自定义数据类型 Temperature,并将其用作序列化属性。

  1. 使用任何模板创建 Unity 项目。

  2. 创建名为 bind-custom-data-type 的文件夹来存储所有文件。

  3. 创建一个名为 Temperature.cs 的 C# 脚本,并将其内容替换为以下代码:

    using System;
    
    namespace UIToolkitExamples
    {
        public enum TemperatureUnit
        {
            Celsius,
            Farenheit
        }
    
        [Serializable]
        public struct Temperature
        {
            public double value;
            public TemperatureUnit unit;
        }
    }
    
  4. 创建一个名为 PlanetScript.cs 的 C# 脚本,并将其内容替换为以下代码:

    using UnityEngine;
    
    namespace UIToolkitExamples
    {
        public class PlanetScript : MonoBehaviour
        {
            public Temperature coreTemperature;
        }
    }
    

创建自定义控件

为 Planet 创建自定义编辑器,为 Temperature 创建自定义属性绘制器 (Property Drawer)。

在自定义属性绘制器中,通过写入 SerializedProperty 的属性(使用 doubleValue 和 enumValueIndex),然后调用 SerializedObject.ApplyModifiedProperties(),实现在华氏温度和摄氏温度之间转换温度的按钮。

自定义属性 Draweris 被视为自定义控件。这是一个以自定义方式行事的内置控件。

  1. 创建一个名为 Editor 的文件夹。

  2. 在 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"));
            }
        }
    }
    
  3. 在 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 文件:

  • DoubleField
  • EnumField
  • Button

将两个字段的 binding-path 设置为 Temperature 属性的 value 和 unit。

  1. 在 Editor 文件夹中,创建一个名为 Resources 的文件夹。

  2. 在 Resources 文件夹中,创建一个名为 temperature_drawer.uxml 的__ UI__(即用户界面,User Interface)让用户能够与您的应用程序进行交互。Unity 目前支持三种 UI 系统。更多信息
    See in Glossary
    文档,并将其内容替换为以下内容:

    <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>
    

测试绑定

  1. 在场景中创建空游戏对象。
  2. 在层级视图 (Hierarchy) 中选择游戏对象。
  3. 将 PlanetScript.cs 拖到检视面板 (Inspector) 上。这会向游戏对象添加一个 Planet Script 组件。
  4. 在 Temperature 字段中输入一个数字,然后从下拉选单中选择单位。
  5. 选择转换 (Convert) 按钮可在单位之间进行转换。如果在 Inspector UI 中作出更改,则自定义控件的 Temperature 属性会更改。

其他资源

绑定自定义控件
支持编辑器 UI