Version: 2020.1
言語: 日本語
ビルトインコントロール
IMGUI のサポート

バインディング

バインディングの目的は、オブジェクト内のプロパティを表示可能な UI に同期することです。バインディングとは、プロパティとそれを変更するビジュアルコントロールの間のリンク (紐づけ) を指します。

バインディングは、オブジェクトと、BindableElement から派生した UIElement、または IBindable インターフェースを実装した UIElement の間で行われます。

UnityEditor.UIElements 名前空間から

基本クラス

  • BaseCompositeField
  • BasePopupField
  • CompoundFields
  • TextValueField

コントロール

  • InspectorElement
  • ProgressBar
  • BoundsField
  • BoundsIntField
  • ColorField
  • CurveField
  • DoubleField
  • EnumField
  • FloatField
  • GradientField
  • IntegerField
  • LayerField
  • LayerMaskField
  • LongField
  • MaskField
  • ObjectField
  • PopupField
  • PropertyControl
  • RectField
  • RectIntField
  • TagField
  • Vector2Field
  • Vector2IntField
  • Vector3Field
  • Vector3IntField
  • Vector4Field

UnityEngine.UIElements 名前空間から

基本クラス

  • BaseField
  • BaseSlider
  • TextInputBaseField
  • TemplateContainer

コントロール

  • Foldout
  • MinMaxSlider
  • Slider
  • SliderInt
  • TextField
  • Toggle

バインドは、上記の名前空間の 1 つからコントロールを使用する際に、以下の手順で行います。

  1. コントロールで、IBindable インターフェースの bindingPath を指定して、どのプロパティをバインドするかが UI にわかるようにします。これは C# または UXML で行うことができます。それぞれの例は、後に紹介します。
  2. バインドされるオブジェクトの SerializedObject を作成します。
  3. このオブジェクトをコントロール、またはその親の 1 つにバインドします。

C# とのバインディング

以下のコードスニペットは C# コードとのバインディングの方法を示しています。このスニペットを使用するには、プロジェクトのエディターフォルダーに C# ファイルとしてこのサンプルを保存します。C# ファイルを SimpleBindingExample.cs と名づけます。

SimpleBindingExample.cs のコンテンツ

using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;

namespace UIElementsExamples
{
   public class SimpleBindingExample : EditorWindow
   {
       TextField m_ObjectNameBinding;
      
       [MenuItem("Window/UIElementsExamples/Simple Binding Example")]
       public static void ShowDefaultWindow()
       {
           var wnd = GetWindow<SimpleBindingExample>();
           wnd.titleContent = new GUIContent("Simple Binding");
       }
    
       public void OnEnable()
       {
           var root = this.rootVisualElement;
           m_ObjectNameBinding = new TextField("Object Name Binding");
           m_ObjectNameBinding.bindingPath = "m_Name";
           root.Add(m_ObjectNameBinding);
           OnSelectionChange();
       }
    
       public void OnSelectionChange()
       {
           GameObject selectedObject = Selection.activeObject as GameObject;
           if (selectedObject != null)
           {
               // シリアル化オブジェクトを作成
               SerializedObject so = new SerializedObject(selectedObject);
               // 階層のルートにバインドします。それはバインドするのに適切なオブジェクトを見つけます。
               rootVisualElement.Bind(so);
    
               // ... または、他の方法として、それを TextField そのものにバインドすることもできます。
               // m_ObjectNameBinding.Bind(so);
           }
           else
           {
               // 実際のビジュアル要素からオブジェクトのバインディングを破棄します
               rootVisualElement.Unbind();
              
               // m_ObjectNameBinding.Unbind();
              
               // バインディングを破棄した後に TextField を消去します
               m_ObjectNameBinding.value = "";
           }
       }
   }
}

Unity で、Window > UIElementsExamples > Simple Binding Example を選択します。このウィンドウを使用してシーンのゲームオブジェクトを選択し、表示された TextField でその名前を変更できます。

UXML とのバインディング

このセクションでは、UXML 階層の設定を通してバインディングの使用法を説明します。

UXML では、属性 binding-path は TextField コントロールで定義されます。binding-pathが、コントロールをオブジェクトの実効プロパティにバインドします。

SimpleBindingExample.uxml のコンテンツ

<UXML xmlns:ui="UnityEngine.UIElements">
 <ui:VisualElement name="top-element">
   <ui:Label name="top-label" text="UXML-Defined Simple Binding"/>
   <ui:TextField name="GameObjectName" label="Name" text="" binding-path="m_Name"/>
 </ui:VisualElement>
</UXML>

SimpleBindingExample.cs のコンテンツ

using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;


namespace UIElementsExamples
{
   public class SimpleBindingExampleUXML : EditorWindow
   {
       [MenuItem("Window/UIElementsExamples/Simple Binding Example UXML")]
       public static void ShowDefaultWindow()
       {
           var wnd = GetWindow<SimpleBindingExampleUXML>();
           wnd.titleContent = new GUIContent("Simple Binding UXML");
       }

       public void OnEnable()
       {
           var root = this.rootVisualElement;
           var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/SimpleBindingExample.uxml");
           visualTree.CloneTree(root);
           OnSelectionChange();
       }
    
       public void OnSelectionChange()
       {
           GameObject selectedObject = Selection.activeObject as GameObject;
           if (selectedObject != null)
           {
               // シリアル化オブジェクトを作成
               SerializedObject so = new SerializedObject(selectedObject);
               // 階層のルートにバインドします。それはバインドするのに適切なオブジェクトを見つけます...
               rootVisualElement.Bind(so);
           }
           else
           {
               // 実際のビジュアル要素からオブジェクトのバインディングを破棄します
               rootVisualElement.Unbind();
              
               // バインディングを破棄した後に TextField を消去します
               // (Q() が null を返す場合、このコードは安全ではありません)
               rootVisualElement.Q<TextField>("GameObjectName").value = "";
           }
       }
   }
}

InspectorElement 内でバインディングを使用

InspectorElement はインスペクターの UIElement です。つまり、特定のタイプの Unity オブジェクトです。InspectorElement を使用してオブジェクトを確認すると、以下の利点があります。

  • UI を作成します。
  • オブジェクトと UI を自動的にバインドします。

別の簡単なバインディングの例は Assets/Editor/SimpleBindingExample.cs にあり、使用例とプロセスの概要を紹介しています。

Assets/Editor/SimpleBindingExample.cs のコンテンツ

using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;

namespace UIElementsExamples
{
   public class SimpleBindingExampleUXML : EditorWindow
   {
       [MenuItem("Window/UIElementsExamples/Simple Binding Example UXML")]
       public static void ShowDefaultWindow()
       {
           var wnd = GetWindow<SimpleBindingExampleUXML>();
           wnd.titleContent = new GUIContent("Simple Binding UXML");
       }

       TankScript m_Tank;
       public void OnEnable()
       {
           m_Tank = GameObject.FindObjectOfType<TankScript>();
           if (m_Tank == null)
               return;
    
           var inspector = new InspectorElement(m_Tank);
           rootVisualElement.Add(inspector);
       }
   }
}

このコードは TankScript スクリプトを参照し、InspectorElement を使用します。TankScript スクリプトは、ゲームオブジェクトに割り当てられた MonoBehaviour の例です。

Assets/TankScript.cs のコンテンツ

using UnityEngine;

[ExecuteInEditMode]
public class TankScript : MonoBehaviour
{
   public string tankName = "Tank";
   public float tankSize = 1;

   private void Update()
   {
       gameObject.name = tankName;
       gameObject.transform.localScale = new Vector3(tankSize, tankSize, tankSize);
   }
}

InspectorElement は、特定の UI でカスタマイズされています。これは、TankEditor スクリプトを使用して実行されます。TankEditor スクリプトは、TankScript 型のカスタムエディターを定義します。TankEditor スクリプトは、階層に UXML ファイルを使用し、USS ファイルを使用してインスペクターのスタイルを設定します。

Assets/Editor/TankEditor.cs のコンテンツ

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

[CustomEditor(typeof(TankScript))]
public class TankEditor : Editor
{
   public override VisualElement CreateInspectorGUI()
   {
       var visualTree = Resources.Load("tank_inspector_uxml") as VisualTreeAsset;
       var uxmlVE = visualTree.CloneTree();
uxmlVE.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Resources/tank_inspector_styles.uss"));
      return uxmlVE;
   }
}

Assets/Resources/tank_inspector_uxml.uxml のコンテンツ

<UXML xmlns:ui="UnityEngine.UIElements" xmlns:ue="UnityEditor.UIElements">
   <ui:VisualElement name="row" class="container">
       <ui:Label text="Tank Script - Custom Inspector" />
       <ue:PropertyField binding-path="tankName" name="tank-name-field" />
       <ue:PropertyField binding-path="tankSize" name="tank-size-field" />
   </ui:VisualElement>
</UXML>

UXMLファイル tank_inspector_uxml.uxml はバインディングを指定します。具体的には、各 PropertyFields タグの各 binding-path 属性が、バインドするプロパティに設定されます。UI に表示される要素は、バインドされた各プロパティのタイプに基づいています。

Assets/Resources/tank_inspector_styles.uss のコンテンツ

.container {
   background-color: rgb(80, 80, 80);
   flex-direction: column;
}
Label {
   background-color: rgb(80, 80, 80);
}
TextField:hover {
   background-color: rgb(255, 255, 0);
}
FloatField {
   background-color: rgb(0, 0, 255);
}

USS ファイル tank_inspector_styles.uss は、各要素のスタイルを定義します。

以下の表は、PropertyField でサポートされているフィールドの一覧です。各フィールドにはデータ型が含まれます。

フィールド
BoundsField Bounds
BoundsIntField BoundsInt
ColorField Color
CurveField AnimationCurve
FloatField float
GradientField Gradient
IntegerField int
IntegerField int (ArraySize 用)
LayerMaskField unit
ObjectField UnityEngine.Object
PopupField<string> Enum
RectField Rect
RectIntField RecInt
TextField string
TextField (maxLength=1) char
Toggle bool
Vector2Field Vector2
Vector2IntField Vector2Int
Vector3Field Vector3
Vector3IntField Vector3Int
Vector4Field Vector4
ビルトインコントロール
IMGUI のサポート