Version: 2021.3
言語: 日本語
カスタムコントロールをバインドする
ViewData の永続性

カスタムコントロールをカスタムデータ型にバインドする

バージョン: 2021.3 以降

この例では、カスタムコントロールをカスタムデータ型にバインドする方法を説明します。

例の概要

この例では、3 つのビルトインコントロールに基づき、カスタムデータ型とカスタムコントロールを作成します。カスタムコントロールは、カスタムデータ型にバインドされます。ドロワーは、Celsius (摂氏) と Fahrenheit (華氏) の変換を行います。

この例で作成するすべてのファイルは、GitHub リポジトリ にあります。

要件

This guide is for developers familiar with the Unity Editor, UI Toolkit, and C# scripting. You are recommended to have a basic understanding of the following:

カスタムデータ型の作成

カスタムデータ型 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 のカスタムプロパティドロワーを作成します。

カスタムプロパティドロワーで、温度を華氏と摂氏間で変換するボタンを実装します。それを行うには、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

2 つのフィールドの binding-pathTemperature プロパティの 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. シーンで空のゲームオブジェクトを作成します。
  2. Hierarchy ウィンドウで、ゲームオブジェクトを選択します。
  3. PlanetScript.cs を Inspector にドラッグします。これにより、Planet Script コンポーネントをゲームオブジェクトに加えます。
  4. Temperature フィールドに数を入力し、ドロップダウンから単位を選択します。
  5. Convert ボタンを選択すると、単位が変換されます。Inspector の UI で変更を加えると、カスタムコントロールの Temperature プロパティが変更されます。

その他の参考資料

カスタムコントロールをバインドする
ViewData の永続性