Version: 2022.3
言語: 日本語
ListView を使わないでリストへバインドする
カスタムコントロールをカスタムデータ型にバインドする

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

バージョン: 2021.3 以降

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

例の概要

この例では、2D 画像を表示するカスタムコントロールを作成します。新しいアセット型のカスタムエディターでカスタムコントロールを使用し、カスタムコントロールを新しい型のアセットのフィールドにバインドします。

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

要件

このガイドは、Unity エディター、UI Toolkit、および C# スクリプトに精通している開発者を対象としています。始める前に、以下をよく理解してください。

シリアル化されたオブジェクトを作成する

Texture2D を含むシリアル化されたオブジェクトを作成します。

  1. 任意のテンプレートで Unity プロジェクトを作成します。

  2. Project ウィンドウで bind-custom-control という名前のフォルダーを作成し、ファイルを保存します。

  3. TextureAsset.cs という名前の C# スクリプトを作成し、そのコンテンツを以下のように置き換えます。`

    using UnityEngine;
    
    namespace UIToolkitExamples
    {
        [CreateAssetMenu(menuName = "UIToolkitExamples/TextureAsset")]
        public class TextureAsset : ScriptableObject
        {
            public Texture2D texture;
    
            public void Reset()
            {
                texture = null;
            }
        }
    }
    

カスタムコントロールの作成とスタイル設定

2D テクスチャアセットへの参照を表すカスタムコントロールを C# で作成し、USS でスタイルを設定します。

  1. フォルダーに Editor という名前のフォルダーを作成します。
  2. Editor フォルダーに、TexturePreviewElement.cs という C# スクリプトを作成します。
  3. TexturePreviewElement.cs の内容を以下に置き換えます。
using System;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;

namespace UIToolkitExamples
{
    public class TexturePreviewElement : BindableElement, INotifyValueChanged<Object>
    {
        public new class UxmlTraits : BindableElement.UxmlTraits { }
        public new class UxmlFactory : UxmlFactory<TexturePreviewElement, UxmlTraits> { }

        public static readonly string ussClassName = "texture-preview-element";

        Image m_Preview;
        ObjectField m_ObjectField;
        Texture2D m_Value;

        public TexturePreviewElement()
        {
            AddToClassList(ussClassName);

            // Create a preview image.
            m_Preview = new Image();
            Add(m_Preview);

            // Create an ObjectField, set its object type, and register a callback when its value changes.
            m_ObjectField = new ObjectField();
            m_ObjectField.objectType = typeof(Texture2D);
            m_ObjectField.RegisterValueChangedCallback(OnObjectFieldValueChanged);
            Add(m_ObjectField);

            styleSheets.Add(Resources.Load<StyleSheet>("texture_preview_element"));
        }
        
        void OnObjectFieldValueChanged(ChangeEvent<Object> evt)
        {
            value = evt.newValue;
        }

        public void SetValueWithoutNotify(Object newValue)
        {
            if (newValue == null || newValue is Texture2D)
            {
                // Update the preview Image and update the ObjectField.
                m_Value = newValue as Texture2D;
                m_Preview.image = m_Value;
                // Notice that this line calls the ObjectField's SetValueWithoutNotify() method instead of just setting
                // m_ObjectField.value. This is very important; you don't want m_ObjectField to send a ChangeEvent.
                m_ObjectField.SetValueWithoutNotify(m_Value);
            }
            else throw new ArgumentException($"Expected object of type {typeof(Texture2D)}");
        }

        public Object value
        {
            get => m_Value;
            // The setter is called when the user changes the value of the ObjectField, which calls
            // OnObjectFieldValueChanged(), which calls this.
            set
            {
                if (value == this.value)
                    return;

                var previous = this.value;
                SetValueWithoutNotify(value);

                using (var evt = ChangeEvent<Object>.GetPooled(previous, value))
                {
                    evt.target = this;
                    SendEvent(evt);
                }
            }
        }
    }
}
  1. Editor フォルダーに、Resources という名前のフォルダーを作成します。

  2. Resources フォルダーに texture_preview_element.uss という名の StyleSheet を作成し、そのコンテンツを以下に置き換えます。

    .texture-preview-element {
        width: 200px;
        height: 200px;
    }
    
    .texture-preview-element > .unity-image {
        flex-grow: 1;
    }
    

Inspector UI の作成

Inspector UI を作成し、カスタムコントロールを Texture2D オブジェクトにバインドします。

  1. Editor フォルダーに TextureAssetEditor.cs という名の C# スクリプトを作成し、そのコンテンツを以下に置き換えます。

    using UnityEditor;
    using UnityEngine.UIElements;
    using UnityEngine;
    
    namespace UIToolkitExamples
    {
        [CustomEditor(typeof(TextureAsset))]
        public class TextureAssetEditor : Editor
        {
            [SerializeField]
            VisualTreeAsset m_VisualTree;
    
            public override VisualElement CreateInspectorGUI()
            {
                return m_VisualTree.CloneTree();
            }
        }
    }
    

UXML でバインディングを設定する

TexturePreviewElement を含む UXML ファイルを作成し、binding-path プロパティを texture に設定します。これにより、TexturePreviewElement は TextureAsset.texture にバインドされます。

  1. Editor フォルダーに texture_asset_editor.uxml という名の UI ドキュメントを作成し、そのコンテンツを以下に置き換えます。

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:example="UIToolkitExamples" editor-extension-mode="True">
        <example:TexturePreviewElement binding-path="texture" />
    </ui:UXML>
    
  2. Project ウィンドウで TextureAssetEditor.cs を選択します。

  3. Inspector で texture_asset_editor.uxmlビジュアルツリー にドラッグします。

バインディングのテスト

  1. メニューから、Assets > Create > UIToolkitExamples > TextureAsset を選択します。これにより、TextureAsset という名前のインスタンスが作成されます。
  2. 新しい TextureAsset オブジェクトを選択します。Inspector で、テクスチャプレビュー要素を見ることができます。フィールドにテクスチャアセットリファレンスを置くと、フィールドの上にプレビューが表示されます。UI のテクスチャプレビュー要素でアセット参照を変更すると、TextureAsset.texture が変更されます。

その他の参考資料

ListView を使わないでリストへバインドする
カスタムコントロールをカスタムデータ型にバインドする