Version: Unity 6.0 (6000.0)
语言 : 中文
使用 C# 脚本创建自定义编辑器窗口
Create a default Inspector

创建自定义检视面板

版本:2022.3+

尽管 MonoBehaviour 和 ScriptableObjects 有一个默认检视面板,但您可能希望为类编写一个自定义检视面板。自定义检视面板可以帮助您执行以下操作:

  • 创建更方便用户的脚本属性表示。
  • 将属性整理和分组在一起。
  • 根据用户的选择显示或隐藏__ UI__(即用户界面,User Interface)让用户能够与您的应用程序进行交互。Unity 目前支持三种 UI 系统。更多信息
    See in Glossary
    的部分。
  • 提供有关各个设置和属性含义的其他信息。

示例概述

此示例将为 MonoBehaviour 类创建自定义检视面板。它同时使用 C# 脚本和 UI Builder 来创建 UI。自定义检视面板还具有自定义属性绘制器。

自定义检视面板显示 Car 类的属性,包括品牌、制造年份、颜色和轮胎列表。检视面板使用 PropertyField 控件显示 Car 类的属性,并使用自定义属性绘制器显示 Tire 类的属性。

可以在此 GitHub 代码仓库中找到此示例创建的完整文件。

先决条件

本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发者。在开始之前,请熟悉以下内容:

新建 MonoBehaviour

要创建自定义检视面板,请首先定义一个继承自 MonoBehaviour 的自定义类。自定义类表示具有多个属性的简单 car

  1. 使用任何模板在 Unity 中创建项目。

  2. 在项目窗口中,创建一个名为 create-a-custom-inspector 的文件夹来存储所有文件。

  3. 创建名为 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;
    }
    
  4. 在场景中创建一个游戏对象,并将 Car 脚本附加到该游戏对象。

    Car 对象的默认检视面板
    Car 对象的默认检视面板

创建自定义检视面板脚本

要为任何序列化对象创建自定义检视面板,需要创建一个派生自 Editor 基类的类,并向其添加 CustomEditor 属性。此属性让 Unity 知道此自定义检视面板代表哪个类。

注意:自定义检视面板脚本必须位于 Editor 文件夹或仅限编辑器的程序集定义中。这是因为对于创建自定义检视面板至关重要的 UnityEditor 命名空间在这些区域之外无法访问。如果尝试创建独立构建时没有遵守此规则,则构建过程会失败。

  1. create-a-custom-inspector 文件夹中创建一个名为 Editor 的文件夹。

  2. Editor 文件夹中创建一个名为 Car_Inspector.cs 的 C# 脚本,其中包含以下内容:

    using UnityEditor;
    using UnityEditor.UIElements;
    using UnityEngine.UIElements;
    
    [CustomEditor(typeof(Car))]
    public class Car_Inspector : Editor
    {
    }
    
  3. 选择附加了 Car 组件的游戏对象。将显示默认检视面板。

  4. 要替换默认检视面板,请在 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;
    }
    
  5. 选择附加了 Car 组件的游戏对象。检视面板现在显示标签 This is a custom Inspector 而不是默认检视面板。

    带有标签的自定义检视面板
    带有标签的自定义检视面板

使用 UI Builder 创建自定义检视面板 UI

可以使用 UI Builder 创建自定义检视面板 UI,并使用 C# 脚本从 UXML 文件加载和实例化 UI。

  1. 要打开 UI Builder,请选择窗口 (Window) > UI 工具包 (UI Toolkit) > UI Builder

  2. 选择文件 (File) > 新建 (New) 以创建新的视觉树资产。

    带有标签的自定义检视面板
    带有标签的自定义检视面板
  3. 在 UI Builder 中启用编辑器专用控件,请在层级 (Hierarchy) 视图中选择该 <unsaved file>*.uxml,然后选中编辑器扩展创作 (Editor Extension Authoring) 复选框。

    带有标签的自定义检视面板
    带有标签的自定义检视面板
  4. 将标签控件从库 (Library) 拖到层级视图 (Hierarchy)。这会向视觉树添加标签控件。

    带有标签的自定义检视面板
    带有标签的自定义检视面板
  5. 在标签控件的检视面板中,更新标签文本。

    带有标签的自定义检视面板
    带有标签的自定义检视面板
  6. 选择文件 (File) > 保存 (Save) 并将视觉树保存为 Assets/create-a-custom-inspector 文件夹的 Car_Inspector_UXML.uxml

在自定义检视面板中使用 UXML

要使用在自定义检视面板中创建的 UXML 文件,请将该文件分配给自定义检视面板,然后在 CreateInspectorGUI() 函数中加载并克隆该文件,然后将其添加到视觉树中。为此,可以使用 CloneTree 方法。可以将任何 VisualElement 作为参数传递,以充当所创建元素的父元素。

  1. Car_Inspector.cs 中,为脚本中的 VisualTreeAsset 创建一个公共变量,并为其分配 Car_Inspector_UXML.uxml

    public VisualTreeAsset m_InspectorXML;
    
  2. 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;
    }
    
  3. 选择附加了 Car 组件的游戏对象。car 组件的检视面板现在显示两个标签:一个通过脚本,一个通过 UI Builder/UXML。

    带有两个标签的自定义检视面板
    带有两个标签的自定义检视面板

绑定文本字段

此自定义检视面板显示 Car 类的所有属性。当用户修改任何 UI 控件时,Car 类实例内的值会发生变化。为此,请将 UI 控件添加到视觉树中,并将其绑定到类的单个属性。

要将控件绑定到序列化属性,请将该属性分配给控件的 binding-path 字段。创建自定义检视面板时,绑定是自动的。CreateInspectorGUI() 会在返回视觉树后进行隐式绑定。有关更多信息,请参阅 SerializedObject 数据绑定

  1. 双击 Car_Inspector_UXML.uxml 可在 UI Builder 中打开。

  2. 添加 TextField 控件。

    向 UI 添加文本字段
    向 UI 添加文本字段
  3. 在 TextField 的检视面板中,将标签文本设置为 Make of the car

  4. 将绑定路径设置为 m_Make

    在 UI Builder 中将属性绑定到控件
    在 UI Builder 中将属性绑定到控件
  5. 将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List) 中,使文本字段与检视面板窗口中的其他字段对齐。有关更多信息,请参阅 BaseField

    向文本字段添加样式类
    向文本字段添加样式类
  6. 在 UI Builder 中,选择文件 (File) > 保存 (Save)

  7. 选择附加了 Car 组件的游戏对象。car 组件的检视面板现在会显示 Make of the car 文本字段。文本字段绑定到 Car 类的 m_Make 属性。

    显示文本字段的自定义检视面板
    显示文本字段的自定义检视面板

绑定属性字段

要显示 Car 类的属性,请为每个字段添加一个控件。控件必须与属性类型匹配。例如,必须将 int 绑定到整数字段或整数滑动条。

可以使用通用 PropertyField 控件,而不是根据属性类型添加特定控件。此控件适用于大多数类型的序列化属性,并会为此属性类型生成默认检视面板 UI。

PropertyField 的优点是,在脚本中更改变量类型时,检视面板 UI 会自动调整。但是,无法在 UI Builder 中预览控件,因为在视觉树绑定到序列化对象之前,控件类型未知。

  1. 双击 Car_Inspector_UXML.uxml 可在 UI Builder 中打开。

  2. Car 类的 m_YearBuilt 属性添加 PropertyField 控件,并设置绑定路径和标签文本。

    在 UI Builder 中添加属性字段
    在 UI Builder 中添加属性字段
  3. 将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List)

  4. Car 类的 m_Color 属性添加 PropertyField 控件,并设置绑定路径和标签文本。

  5. 将样式类 unity-base-field__aligned 添加到样式类列表 (Style Class List)

  6. 在 UI Builder 中,选择文件 (File) > 保存 (Save)

  7. 选择包含 Car 组件的游戏对象。car 组件的检视面板现在会显示 Year BuiltPaint Color 属性字段。

    带有属性字段的自定义检视面板
    带有属性字段的自定义检视面板

创建自定义属性绘制器

自定义属性绘制器是自定义可序列化类的自定义检视面板 UI。如果该可序列化类是另一个序列化对象的一部分,则自定义 UI 会在检视面板中显示该属性。在 UI 工具包中,PropertyField 控件显示字段的自定义属性绘制器(如果有)。

  1. 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;
    }
        
    
  2. 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];
    }
    
  3. 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>
        
    
  4. 选择具有 Car 组件的游戏对象。car 组件的检视面板现在会显示 Tires 属性字段。

    使用 PropertyField 控件显示数组
    使用 PropertyField 控件显示数组

为自定义属性绘制器创建 UI

可以创建一个自定义属性绘制器来自定义列表中各个 Tire 元素的外观。自定义属性绘制器不是派生自 Editor 基类,而是派生自 PropertyDrawer 类。

可以使用 C# 脚本或 UXML 为属性创建 UI。此示例使用 C# 脚本来创建自定义 UI。要为自定义属性创建 UI,请覆盖 CreatePropertyGUI 方法。

  1. 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;
        }
    }
    
  2. 选择包含 Car 组件的游戏对象。car 组件的检视面板现在显示带有自定义属性绘制器的 Tires 属性字段。

    使用自定义属性绘制器的检视面板
    使用自定义属性绘制器的检视面板

创建默认检视面板

创建一个 Foldout 控件以显示默认的检视面板 UI。要将默认检视面板 UI 附加到 Foldout,必须获取对它的引用。可以使用 UQuery 从检视面板的视觉树中检索 Foldout 的视觉元素,并使用 InspectorElement 类的 FillDefaultInspector 方法将默认检视面板 UI 附加到 Foldout 控件。

  1. 双击 Car_Inspector_UXML.uxml 文件可在 UI Builder 中打开该文件。

  2. 将 Foldout 控件添加到 UI,将其命名为 Default_Inspector,并设置标签文本:

    默认检视面板的 Foldout
    默认检视面板的 Foldout
  3. 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;
        }
    }
        
    
  4. 选择包含 Car 组件的游戏对象。car 组件的检视面板现在会显示 Default Inspector Foldout,其中包含默认检视面板 UI。

    具有默认检视面板的检视面板
    具有默认检视面板的检视面板

其他资源

使用 C# 脚本创建自定义编辑器窗口
Create a default Inspector