版本:Unity 6 (6000.0)
语言:英语
绑定自定义控件
对编辑器 UI 的支持

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

版本: 2021.3+

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

示例概述

此示例创建了一个自定义数据类型和一个基于三个内置控件的自定义控件。它将自定义控件绑定到自定义数据类型。绘图器在摄氏度和华氏度之间进行转换。

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

先决条件

本指南适用于熟悉 Unity 编辑器、UI(用户界面) 允许用户与您的应用程序交互。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 创建一个自定义编辑器和一个自定义 属性绘制器Unity 的一项功能,允许您通过在脚本上使用属性或通过控制特定可序列化类应如何显示来自定义 Inspector 窗口中某些控件的外观 更多信息
请参阅 术语表
用于 Temperature

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

自定义属性绘制器被视为自定义控件。它是一个以自定义方式运行的内置控件。

  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 属性的 valueunit

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

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

测试绑定

  1. 场景场景包含游戏中的环境和菜单。可以将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,您放置环境、障碍物和装饰,从本质上讲是分段设计和构建游戏。 更多信息
    请参阅 术语表
    中创建一个空的 游戏对象Unity 场景中的基本对象,可以表示角色、道具、场景、摄像机、路径点等。游戏对象的功能由附加到它的组件定义。 更多信息
    请参阅 术语表
  2. 在层次结构中,选择游戏对象。
  3. PlanetScript.cs 拖到 Inspector一个 Unity 窗口,显示有关当前选定的游戏对象、资产或项目设置的信息,允许您检查和编辑值。 更多信息
    请参阅 术语表
    。这会向游戏对象添加一个 Planet Script 组件。
  4. Temperature 字段中输入一个数字,并从下拉列表中选择一个单位。
  5. 选择 Convert 按钮在单位之间进行转换。如果在 Inspector UI 中进行更改,则自定义控件的 Temperature 属性也会发生更改。

其他资源

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