Version: 2019.4
内置控件
支持 IMGUI

绑定

绑定的目的是将对象内的属性同步到可见的 UI。 _绑定_是指属性和对属性进行修改的可视化控件之间的链接。

绑定是在对象和任何从 BindableElement 派生的或实现 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. 在 Control 中,从 IBindable 接口指定 bindingPath,以便 UI 知道要绑定的属性。为此,可使用 C# 或 UXML。本主题的后面部分提供了每种情况下的示例。
  2. 为绑定的对象创建一个 SerializedObject。
  3. 将此对象绑定到 UIElements 控件或其父项之一。

使用 C# 进行绑定

以下代码片段显示了如何使用 C# 代码创建绑定。要使用此代码片段,请将本示例作为 C# 文件保存在项目的 Editor 文件夹中。将该 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 控件中进行定义。就是这个属性会将控件绑定到对象的有效属性。

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 是用于特定类型 Unity 对象的 Inspector 的 UIElement 对应元素。使用 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 脚本并使用 InspectorElementTankScript 脚本是分配给一个游戏对象的 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 文件对 Inspector 进行样式设置。

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 属性 (attribute) 都设置为要绑定的属性 (property)。UI 中显示的元素基于每个被绑定属性 (property) 的类型。

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 支持的字段。每个字段都包含其数据类型。

字段 Type
BoundsField Bounds
BoundsIntField BoundsInt
ColorField Color
CurveField AnimationCurve
FloatField 浮点精度
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