版本:2022.3+
尽管 MonoBehaviour 和 ScriptableObjects 有一个默认检视面板,但您可能希望为类编写一个自定义检视面板。自定义检视面板可以帮助您执行以下操作:
此示例将为 MonoBehaviour 类创建自定义检视面板。它同时使用 C# 脚本和 UI Builder 来创建 UI。自定义检视面板还具有自定义属性绘制器。
自定义检视面板显示 Car 类的属性,包括品牌、制造年份、颜色和轮胎列表。检视面板使用 PropertyField 控件显示 Car 类的属性,并使用自定义属性绘制器显示 Tire 类的属性。
可以在此 GitHub 代码仓库中找到此示例创建的完整文件。
本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发者。在开始之前,请熟悉以下内容:
要创建自定义检视面板,请首先定义一个继承自 MonoBehaviour 的自定义类。自定义类表示具有多个属性的简单 car。
使用任何模板在 Unity 中创建项目。
在项目窗口中,创建一个名为 create-a-custom-inspector 的文件夹来存储所有文件。
创建名为 Car.cs 的 C# 脚本,其中包含以下内容:
using UnityEngine;
public class Car : MonoBehaviour
{
public string m_Make = "Toyota";
public int m_YearBuilt = 1980;
public Color m_Color = Color.black;
}
在场景中创建一个游戏对象,并将 Car 脚本附加到该游戏对象。
要为任何序列化对象创建自定义检视面板,需要创建一个派生自 Editor 基类的类,并向其添加 CustomEditor 属性。此属性让 Unity 知道此自定义检视面板代表哪个类。
注意:自定义检视面板脚本必须位于 Editor 文件夹或仅限编辑器的程序集定义中。这是因为对于创建自定义检视面板至关重要的 UnityEditor 命名空间在这些区域之外无法访问。如果尝试创建独立构建时没有遵守此规则,则构建过程会失败。
在 create-a-custom-inspector 文件夹中创建一个名为 Editor 的文件夹。
在 Editor 文件夹中创建一个名为 Car_Inspector.cs 的 C# 脚本,其中包含以下内容:
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomEditor(typeof(Car))]
public class Car_Inspector : Editor
{
}
选择附加了 Car 组件的游戏对象。将显示默认检视面板。
要替换默认检视面板,请在 Car_Inspector 类中添加以下代码以覆盖 CreateInspectorGUI() 并返回包含 UI 的新视觉元素:
public override VisualElement CreateInspectorGUI()
{
// Create a new VisualElement to be the root of our Inspector UI.
VisualElement myInspector = new VisualElement();
// Add a simple label.
myInspector.Add(new Label("This is a custom Inspector"));
// Return the finished Inspector UI.
return myInspector;
}
选择附加了 Car 组件的游戏对象。检视面板现在显示标签 This is a custom Inspector 而不是默认检视面板。
可以使用 UI Builder 创建自定义检视面板 UI,并使用 C# 脚本从 UXML 文件加载和实例化 UI。
要打开 UI Builder,请选择窗口 (Window) > UI 工具包 (UI Toolkit) > UI Builder。
选择文件 (File) > 新建 (New) 以创建新的视觉树资产。
要在 UI Builder 中启用编辑器专用控件,请在层级 (Hierarchy) 视图中选择该 <unsaved file>*.uxml,然后选中编辑器扩展创作 (Editor Extension Authoring) 复选框。
将标签控件从库 (Library) 拖到层级视图 (Hierarchy)。这会向视觉树添加标签控件。
在标签控件的检视面板中,更新标签文本。
选择文件 (File) > 保存 (Save) 并将视觉树保存为 Assets/create-a-custom-inspector 文件夹的 Car_Inspector_UXML.uxml。
要使用在自定义检视面板中创建的 UXML 文件,请将该文件分配给自定义检视面板,然后在 CreateInspectorGUI() 函数中加载并克隆该文件,然后将其添加到视觉树中。为此,可以使用 CloneTree 方法。可以将任何 VisualElement 作为参数传递,以充当所创建元素的父元素。
在 Car_Inspector.cs 中,为脚本中的 VisualTreeAsset 创建一个公共变量,并为其分配 Car_Inspector_UXML.uxml。
public VisualTreeAsset m_InspectorXML;
将 CreateInspectorGUI() 方法更新为以下内容:
public override VisualElement CreateInspectorGUI()
{
// Create a new VisualElement to be the root of our Inspector UI.
VisualElement myInspector = new VisualElement();
// Add a simple label.
myInspector.Add(new Label("This is a custom Inspector"));
// Load the UXML file.
m_InspectorXML= AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/create-a-custom-inspector/Car_Inspector_UXML.uxml");
// Instantiate the UXML.
myInspector = m_InspectorXML.Instantiate();
// Return the finished Inspector UI.
return myInspector;
}
选择附加了 Car 组件的游戏对象。car 组件的检视面板现在显示两个标签:一个通过脚本,一个通过 UI Builder/UXML。
此自定义检视面板显示 Car 类的所有属性。当用户修改任何 UI 控件时,Car 类实例内的值会发生变化。为此,请将 UI 控件添加到视觉树中,并将其绑定到类的单个属性。
要将控件绑定到序列化属性,请将该属性分配给控件的 binding-path 字段。创建自定义检视面板时,绑定是自动的。CreateInspectorGUI() 会在返回视觉树后进行隐式绑定。有关更多信息,请参阅 SerializedObject 数据绑定。
双击 Car_Inspector_UXML.uxml 可在 UI Builder 中打开。
添加 TextField 控件。
在 TextField 的检视面板中,将标签文本设置为 Make of the car。
将绑定路径设置为 m_Make。
将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List) 中,使文本字段与检视面板窗口中的其他字段对齐。有关更多信息,请参阅 BaseField。
在 UI Builder 中,选择文件 (File) > 保存 (Save)。
选择附加了 Car 组件的游戏对象。car 组件的检视面板现在会显示 Make of the car 文本字段。文本字段绑定到 Car 类的 m_Make 属性。
要显示 Car 类的属性,请为每个字段添加一个控件。控件必须与属性类型匹配。例如,必须将 int 绑定到整数字段或整数滑动条。
可以使用通用 PropertyField 控件,而不是根据属性类型添加特定控件。此控件适用于大多数类型的序列化属性,并会为此属性类型生成默认检视面板 UI。
PropertyField 的优点是,在脚本中更改变量类型时,检视面板 UI 会自动调整。但是,无法在 UI Builder 中预览控件,因为在视觉树绑定到序列化对象之前,控件类型未知。
双击 Car_Inspector_UXML.uxml 可在 UI Builder 中打开。
为 Car 类的 m_YearBuilt 属性添加 PropertyField 控件,并设置绑定路径和标签文本。
将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List)。
为 Car 类的 m_Color 属性添加 PropertyField 控件,并设置绑定路径和标签文本。
将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List)。
在 UI Builder 中,选择文件 (File) > 保存 (Save)。
选择包含 Car 组件的游戏对象。car 组件的检视面板现在会显示 Year Built 和 Paint Color 属性字段。
自定义属性绘制器是自定义可序列化类的自定义检视面板 UI。如果该可序列化类是另一个序列化对象的一部分,则自定义 UI 会在检视面板中显示该属性。在 UI 工具包中,PropertyField 控件显示字段的自定义属性绘制器(如果有)。
在 create-a-custom-inspector 文件夹中,创建一个名为 Tire.cs 的新脚本,其中包含以下内容:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Tire
{
public float m_AirPressure = 21.5f;
public int m_ProfileDepth = 4;
}
在 Car.cs 中,向 Car 类添加列表 Tire。完成的 Car.cs 文件如下所示:
using UnityEngine;
public class Car : MonoBehaviour
{
public string m_Make = "Toyota";
public int m_YearBuilt = 1980;
public Color m_Color = Color.black;
// This car has four tires.
public Tire[] m_Tires = new Tire[4];
}
PropertyField 控件适用于所有标准属性类型,并支持自定义的可序列化类和数组。要显示汽车轮胎的属性,请在 Car_Inspector_UXML.uxml 中添加另一个 PropertyField 并将其绑定到 m_Tires。完成的 Car_Inspector_UXML.uxml 文件如下所示:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
<ui:TextField picking-mode="Ignore" label="Make of the car" value="filler text" binding-path="m_Make" class="unity-base-field__aligned" />
<uie:PropertyField binding-path="m_YearBuilt" label="Year Built" class="unity-base-field__aligned" />
<uie:PropertyField binding-path="m_Color" label="Paint Color" class="unity-base-field__aligned" />
<uie:PropertyField label="Tires" binding-path="m_Tires" class="unity-base-field__aligned" />
</ui:UXML>
选择具有 Car 组件的游戏对象。car 组件的检视面板现在会显示 Tires 属性字段。
可以创建一个自定义属性绘制器来自定义列表中各个 Tire 元素的外观。自定义属性绘制器不是派生自 Editor 基类,而是派生自 PropertyDrawer 类。
可以使用 C# 脚本或 UXML 为属性创建 UI。此示例使用 C# 脚本来创建自定义 UI。要为自定义属性创建 UI,请覆盖 CreatePropertyGUI 方法。
在 Editor 文件夹中,创建一个名为 Tire_PropertyDrawer.cs 的新脚本,其中包含以下内容:
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomPropertyDrawer(typeof(Tire))]
public class Tire_PropertyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
// Create drawer UI using C#.
var popup = new UnityEngine.UIElements.PopupWindow();
popup.text = "Tire Details";
popup.Add(new PropertyField(property.FindPropertyRelative("m_AirPressure"), "Air Pressure (psi)"));
popup.Add(new PropertyField(property.FindPropertyRelative("m_ProfileDepth"), "Profile Depth (mm)"));
// Return the finished UI.
return popup;
}
}
选择包含 Car 组件的游戏对象。car 组件的检视面板现在显示带有自定义属性绘制器的 Tires 属性字段。
创建一个 Foldout 控件以显示默认的检视面板 UI。要将默认检视面板 UI 附加到 Foldout,必须获取对它的引用。可以使用 UQuery 从检视面板的视觉树中检索 Foldout 的视觉元素,并使用 InspectorElement 类的 FillDefaultInspector 方法将默认检视面板 UI 附加到 Foldout 控件。
双击 Car_Inspector_UXML.uxml 文件可在 UI Builder 中打开该文件。
将 Foldout 控件添加到 UI,将其命名为 Default_Inspector,并设置标签文本:
在 Car_Inspector.cs 文件中,更新 CreateInspectorGUI() 方法以获取对 Default_Inspector Foldout 的引用,并将默认检视面板 UI 附加到该文件。完成的 Car_Inspector.cs 文件如下所示:
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomEditor(typeof(Car))]
public class Car_Inspector : Editor
{
public VisualTreeAsset m_InspectorUXML;
public override VisualElement CreateInspectorGUI()
{
// Create a new VisualElement to be the root of our Inspector UI.
VisualElement myInspector = new VisualElement();
// Add a simple label.
myInspector.Add(new Label("This is a custom Inspector"));
// Load the UXML file and clone its tree into the inspector.
if (m_InspectorUXML != null)
{
VisualElement uxmlContent = m_InspectorUXML.CloneTree();
myInspector.Add(uxmlContent);
}
// Return the finished Inspector UI.
return myInspector;
}
}
选择包含 Car 组件的游戏对象。car 组件的检视面板现在会显示 Default Inspector Foldout,其中包含默认检视面板 UI。