【Unity基础】初识UI Toolkit - 编辑器UI

(本文所需图片在文章上面的资源中,点击“立即下载”。)

本文介绍了如何通过UI工具包(UI Toolkit)来创建一个编辑器UI。

一、创建项目

1. 打开Unity创建一个空项目(任意模板),这里我们以URP 3D为例。

2. 在项目的Assets文件夹中,新建一个文件夹Editor,并在Editor中新建一个文件夹Resources。我们将把脚本放在Assets/Editor中,其他资源文件放在Assets/Editor/Resources中。(关于Unity中的特殊文件夹,请参见这篇文章)

3. 右键点击Editor文件夹,选择Create > UI Toolkit > Editor Window

4. 将本文资源中几个图标文件下载后存放在Editor/Resources/Icons中。

二、创建项目

接下来我们将创建编辑器窗体并将其添加到Unity的菜单中。

1. 在UI Toolkit Editor Window Creator中,在C#一栏输入QuickTool,并且取消勾选UXML和USS。如下图所示。(当然你也可以不取消勾选这两项,那么将会自动创建UXML和USS文件。不过在这篇文章中,我们将手动创建这两个文件。)

2. 点击“Confirm”保存,以创建Editor窗体。

3. 现在我们将设置窗体的大小以及在菜单中的位置。打开QuickTool.cs文件(以Visual Studio为例),并将其中的MenuItem和ShowExample部分用下面的代码替换。

public class QuickTool : EditorWindow

{

    [MenuItem("QuickTool/Open _%#T")]

    public static void ShowWindow()

    {

        // Opens the window, otherwise focuses it if it's already open.

        var window = GetWindow<QuickTool>();

        // Adds a title to the window.

        window.titleContent = new GUIContent("QuickTool");

        // Sets a minimum size to the window.

        window.minSize = new Vector2(280, 50);

}

}

说明:代码中MenuItem字符串末尾的_%#T,是为了添加一个打开窗口的快捷键,在Windows中是Ctrl+ Shift + T(在Mac上是Command + Shift + T)

4. 保存代码并返回Unity。这时你将在菜单中看到QuickTool。点击QuickTool > Open,将打开新建的Editor窗口。

三、搭建UI

在UI工具包中,用户界面是由单个的可视化元素组成。多个界面元素设计并组合到UI模板文件中,也是就*.uxml文件中。一个UXML文件存储所有界面元素的结构,样式和布局。这种组合的方式在Unity中被称为可视化树(Visual Tree)。

一个UI界面是由一个或多个Visual Tree组成的。一个界面或Panel中会保存一个对根元素的引用,被称谓rootVisualElement。而通过UI模板文件或C#脚本创建的Visual Tree将被添加到这个根元素下面,这样就可以显示在屏幕上。

每一个EditorWindow都会将所有的UI元素保存在rootVisualElement中。

通过脚本来创建界面元素

在我们进入UXML之前,先来看看如何通过脚本创建界面元素。

在QuickTool.cs文件中,找到QuickTool类,它里面有一个CreateGUI()方法。这个方法就包括了对rootVisualElement的引用,并将一个label显示在窗体中。

当然你也可以在这里添加更多的页面元素。下面的代码将添加一个按钮,并将其大小设置为160x30 px。

private void CreateGUI()

{

    // Reference to the root of the window.

    var root = rootVisualElement;

    // Creates our button and sets its Text property.

    var myButton = new Button() { text = "My Button" };

    // Give it some style.

    myButton.style.width = 160;

    myButton.style.height = 30;

    // Adds it to the root.

    root.Add(myButton);

}

保存代码并返回到Unity,现在窗体将显示为如下图所示的样子。

我们可以通过C#脚本添加更多的页面元素。但是当界面变得复杂时,通过这种方式将增加维护的难度。Unity推荐的方法是,使用UXML单独保存页面元素,使用USS保存样式,并在C#中加载UI模板和添加对元素行为的控制以及数据绑定关系。

下面先删除或注释掉CreateGUI()方法中的代码,我们将先创建一个新的UXML文件。

创建UXML文件

接下来我们将创建一个单独的UXML文件。

当然比较高效的方法是先创建一个可重用的UI模板,然后就可以在其他模板中反复调用来创建新元素。下面我们将创建两个模板:

  • ButtonTemplate:保存带有图标的按钮。
  • QuickTool_Main:保存将添加到rootVisualElement中的UI结构。它将通过button模板创建5个工具栏按钮,并进行布局。

1. 在Unity中,在Project中找到Assets/Editor/Resources文件夹。从菜单中,选择Assets > Create > UI Toolkit > UI Document。这样就会在文件夹中新建一个UXML文件。

2. 将这个文件命名为ButtonTemplate

3. 重复上面的过程,再新建一个UXML文件,并命名为QuickTool_Main

说明:双击UXML文件会打开UIBuilder窗口,如果想在文本编辑器中打开文件,需要点击文件右侧的箭头,并双击inlineStyle(将用Unity中关联的默认代码编辑器打开,比如Visual Studio)。

4. 在文本编辑器打开ButtonTemplate.uxml文件,并将内容替换为下面的代码:

<UXML xmlns="UnityEngine.UIElements">

  <!-- Creates the button. -->

  <VisualElement class="quicktool-button unity-button">      

    <!-- Adds a VisualElement child (corresponding to the button's icon). -->

    <VisualElement class="quicktool-button-icon"/>   

  </VisualElement>

</UXML>

上面的UXML代码将创建一个带有图标的按钮。这个按钮和图标在UXML中有不同的名称。添加名称的目的主要是:

  • 通过脚本访问元素
  • 为这些元素添加样式

5. 下一步,利用上面的button模板创建UI。打开QuickTool_Main.uxml文件,并将其内容用下面代码替换。

<UXML xmlns="UnityEngine.UIElements">

  <!-- Creates our template and gives it a name for future reference. -->

  <Template path="Assets/Editor/Resources/ButtonTemplate.uxml" name="button-template" />

  <!-- Creates a parent VisualElement inside which we will use our button template. -->

  <VisualElement class="buttons-container">

    <!-- Instantiates the template multiple times. Each time, we give it a name for future reference. -->

    <Instance template="button-template" name="Cube"/>

    <Instance template="button-template" name="Sphere"/>

    <Instance template="button-template" name="Capsule"/>

    <Instance template="button-template" name="Cylinder"/>

    <Instance template="button-template" name="Plane"/>

  </VisualElement>

</UXML>

这个UXML中包括了5个以button模板创建的按钮。每一个按钮都有不同的UXML标签名称。后面我们将通过这些名称来创建不同的基础对象。务必确保这些名称和上面的代码完全一致,否则在后面使用时将会出错。

四、创建脚本

上面我们已经完成了UXML的内容。接下来将开始编写C#脚本。

1. 打开QuickTool.cs文件,将其中CreateUI()的内容用下面的代码替换。

    private void CreateGUI()

    {

        // Reference to the root of the window.

        var root = rootVisualElement;

        // Loads and clones our VisualTree (eg. our UXML structure) inside the root.

        var quickToolVisualTree = Resources.Load<VisualTreeAsset>("QuickTool_Main");

        quickToolVisualTree.CloneTree(root);

        // Queries all the buttons (via class name) in our root and passes them

        // in the SetupButton method.

        var toolButtons = root.Query(className: "quicktool-button");

        toolButtons.ForEach(SetupButton);

    }

上面的CreateGUI()方法将加载UI模板并用Clone()方法创建元素将其添加到窗体的根元素中。然后通过SetupButton()方法来创建工具栏中的多个按钮。

2. 在QuickTool.cs中,创建SetupButton方法。

private void SetupButton(VisualElement button)

    {

        // Reference to the VisualElement inside the button that serves

        // as the button's icon.

        var buttonIcon = button.Q(className: "quicktool-button-icon");

        // Icon's path in our project.

        var iconPath = "Icons/" + button.parent.name + "_icon";

        // Loads the actual asset from the above path.

        var iconAsset = Resources.Load<Texture2D>(iconPath);

        // Applies the above asset as a background image for the icon.

        buttonIcon.style.backgroundImage = iconAsset;

        // Instantiates our primitive object on a left click.

        button.RegisterCallback<PointerUpEvent, string>(CreateObject, button.parent.name);

        // Sets a basic tooltip to the button itself.

        button.tooltip = button.parent.name;

    }

SetupButton()方法检索到按钮下方的VisualElement(可视化元素)引用,该元素用于容纳按钮的图标。它通过Q()方法以及在UXML文件中指定的类名quicktool-button-icon来获取元素。接着,将一个图像分配给该元素。同时,它还为按钮分配了一个回调方法,该方法会在用户点击按钮时触发。

3. 在QuickTool.cs文件最前面添加using System的命名。

4. 在QuickTool类中,创建一个CreateObject回调方法。这是一个根据按钮名称来创建基础对象的简单方法。

    private void CreateObject(PointerUpEvent _, string primitiveTypeName)

    {

        var pt = (PrimitiveType)Enum.Parse

                     (typeof(PrimitiveType), primitiveTypeName, true);

        var go = ObjectFactory.CreatePrimitive(pt);

        go.transform.position = Vector3.zero;

    }

5. 保存代码并返回Unity。当打开窗体时,你将看到按钮显示出来,但是没有图标并且没有按横向排列。在下面这一部分我们将进一步完善。

五、设计样式

每一个VisualElement(可视化元素)都可以通过样式属性来影响其在屏幕上显示的效果。这些样式属性既可以在C#脚本中直接设置,也可以通过样式来设置。除了布局属性外,还有像backgroundImage或borderColor这些影响显示效果的属性。

在Unity中是通过USS文件来保存样式表的。在USS文件中可以定义多个部分。主要有:

  • 以 “.”开始,将匹配类(所有包括了有特定class属性名称的元素)。
  • 以 “#”开始,将匹配VisualElement名称(不是唯一的)。
  • 简单的按C#中的类型匹配。

说明:为了简单起见,我们将为整个窗体使用一个样式文件。当然,如果需要的话,你也可以使用多个样式文件。

1. 在Unity的Project中,找到Assets > Editor > Resources

2. 通过菜单Assets > Create > UI Toolkit > Style Sheet创建一个新的USS文件,并命名为QuickTool_Style

3. 在样式文件中,添加下面样式,用于button容器。

.buttons-container {

    /* Populates the elements in this container horizontally. */

    flex-direction: row;

    /* Makes the content of the container wrap when resized. */

    flex-wrap: wrap;

}

说明:这里我们只是在设置Flex属性。这是任何UI Toolkit布局的核心,理解其工作流程是必不可少的。要了解更多关于Flex属性的信息,点击此处。

4. 为button和图标创建样式。

.quicktool-button {

    width: 50px;

    height: 50px;

    /* Style rule that aligns items on the horizontal axis. */

    align-items: flex-start;

    /* Style rule that aligns items on the vertical axis. */

    justify-content: center;

}

.quicktool-button-icon {

    height: 40px;

    width: 40px;

    opacity: 0.8;

}

/* How the icon should behave when hovered. */

.quicktool-button-icon:hover {

    opacity: 1;

}

/* How the icon should behave when its parent button is clicked. */

.quicktool-button:active > .quicktool-button-icon {

    opacity: 0.6;

}

说明:在C#脚本中定义的样式将覆盖USS文件中对应的样式。比如,你在USS文件中设置了margin-top:5,在C#脚本中设置了VisualElement.style.marginTop=2,那么这个元素将使用VisualElement.style.marginTop =2。

5. 最后,我们将通过VisualElement.styleSheets.Add()方法将样式与VisualElement关联起来。在QuickTool.cs中,将CreateGUI()方法更新成如下。

private void CreateGUI()

{

    // Reference to the root of the window.

    var root = rootVisualElement;

    // Associates a stylesheet to our root. Thanks to inheritance, all root’s

    // children will have access to it.

    root.styleSheets.Add(Resources.Load<StyleSheet>("QuickTool_Style"));

    // Loads and clones our VisualTree (eg. our UXML structure) inside the root.

    var quickToolVisualTree = Resources.Load<VisualTreeAsset>("QuickTool_Main");

    quickToolVisualTree.CloneTree(root);

    // Queries all the buttons (via type) in our root and passes them

    // in the SetupButton method.

    var toolButtons = root.Query(className: "quicktool-button");

    toolButtons.ForEach(SetupButton);

}

说明:对样式表的更改将对运行中的Editor窗口立即生效。样式可以附件到任何VisualElement上,并可以应用到这个容器内的所有子元素上。

6. 保存文件并返回Unity。

现在这个自定义的Editor窗体已经完成。我们可以看到一个小的横向排列的工具栏,点击上面的按钮将在场景中创建对应的基础对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904214.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NVR小程序接入平台/设备EasyNVR多个NVR同时管理多平台级联与上下级对接的高效应用

政务数据共享平台的建设正致力于消除“信息孤岛”现象&#xff0c;打破“数据烟囱”&#xff0c;实现国家、省、市及区县数据的全面对接与共享。省市平台的“级联对接”工作由多级平台共同构成&#xff0c;旨在满足跨部门、跨层级及跨省数据共享的需求&#xff0c;推动数据流通…

Android 获取OAID

获取OAID 老规矩&#xff0c;直接上&#xff1a; implementation com.huawei.hms:opendevice:6.11.0.300 // 要获取华为vaid 和aaid&#xff0c;还需添加opendevice 依赖implementation(name: oaid_sdk_2.5.0, ext: aar) import android.content.Context; import android.util.…

Flume采集Kafka数据到Hive

版本&#xff1a; Kafka&#xff1a;2.4.1 Flume&#xff1a;1.9.0 Hive&#xff1a;3.1.0 Kafka主题准备&#xff1a; Hive表准备&#xff1a;确保hive表为&#xff1a;分区分桶、orc存储、开启事务 Flume准备&#xff1a; 配置flume文件&#xff1a; /opt/datasophon/flume-1…

还在担心你收藏的书签下架或失效?试试这款自托管书签管理器『Linkwarden』吧!

还在担心你收藏的书签下架或失效&#xff1f;试试这款自托管书签管理器『Linkwarden』吧&#xff01; 哈喽&#xff0c;小伙伴儿们好&#xff0c;我是Stark-C~ 随着大家在网上收藏的浏览器书签越来越多&#xff0c;难免会导致管理混乱的问题。可能会在我们需要的时候难以找到…

MySQL与金蝶云星空数据集成,实现生产用料清单自动刷新

MySQL数据集成到金蝶云星空&#xff1a;zz-生产用料清单主动刷新 在企业的日常运营中&#xff0c;数据的及时性和准确性至关重要。为了实现MySQL数据库与金蝶云星空系统之间的数据无缝对接&#xff0c;我们设计并实施了一个名为“zz-生产用料清单主动刷新”的集成方案。本案例…

八,Linux基础环境搭建(CentOS7)- 安装Mysql和Hive

Linux基础环境搭建&#xff08;CentOS7&#xff09;- 安装Mysql和Hive 大家注意以下的环境搭建版本号&#xff0c;如果版本不匹配有可能出现问题&#xff01; 一、Mysql下载及安装 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Orac…

计算机毕业设计Python+大模型恶意木马流量检测与分类 恶意流量监测 随机森林模型 深度学习 机器学习 数据可视化 大数据毕业设计 信息安全 网络安全

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; Python大模型恶意木马流量检…

Conditional DETR论文笔记

原文链接 [2108.06152] Conditional DETR for Fast Training Convergencehttps://arxiv.org/abs/2108.06152 原文笔记 What 《Conditional DETR for Fast Training Convergence》 这个工作也是针对于DETR Query的工作 用于解决DETR训练收敛慢&#xff08;Object query需要…

LoRA微调,真的有毒!

本文介绍一篇相当有意思的文章&#xff0c;该文章的内容对我们使用指令微调将预训练模型改造为 Chat 模型和下游专业模型相当有指导意义。 本文的标题听起来有些唬人&#xff0c;有些标题党&#xff0c;但是这个论点在一定的限定条件下是成立的&#xff0c;笔者归纳为&#xf…

Qt——信号和槽

一.信号和槽概述 谈及信号&#xff0c;很容易联想到在Linux系统中所分享到的信号。那么Linux信号和Qt信息有什么不同&#xff1f; 在 Qt 中&#xff0c;用户和控件的每次交互过程称为⼀个事件。比如 "用户点击按钮" 是⼀个事件&#xff0c;"用户关 闭窗口&quo…

Nginx反向代理(下)

1. WebSocket的反向代理 WebSocket 是目前比较成熟的技术了, WebSocket 协议为创建客户端和服务器端需要实时双向通讯的 webapp 提供了一个选择。服务器可以向浏览器推送相关消息&#xff0c;这样在前端实现的某个页面中我们可以及时看到服务器的状态变化而不用使用定时刷新去…

2024年10月中国数据库排行榜:TiDB续探花,GaussDB升四强

10月中国数据库流行度排行榜如期发布&#xff0c;再次印证了市场分层的加速形成。国家数据库测评结果已然揭晓&#xff0c;本批次通过的产品数量有限&#xff0c;凸显了行业标准的严格与技术门槛的提升。再看排行榜&#xff0c;得分差距明显增大&#xff0c;第三名与后续竞争者…

【C++】RBTree——红黑树

文章目录 一、红黑树的概念1.1 红⿊树的规则&#xff1a;1.2 理解最长路径长度不超过最短路径长度的 2 倍1.3 红⿊树的效率 二、 红⿊树的实现2.1 红⿊树的结构2.2 红⿊树的插⼊2.2.1 红⿊树树插⼊⼀个值的⼤概过程 2.3 红⿊树的插⼊代码实现 一、红黑树的概念 红⿊树是⼀棵⼆…

git下载和配置

git是什么&#xff1f; Git是一种分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;尤其是源代码。它允许多个开发者在同一项目上进行协作&#xff0c;同时保持代码的历史记录。Git的主要特点包括&#xff1a; 分布式&#xff1a;每个开发者都有项目的完整副本&a…

[MySQL#6] 表的CRUD (1) | Create | Retrieve(查) | where

目录 1. 插入 1.1 单行数据 - 全列插入 指定列插入 1.2 多行数据 - 全列插入 指定列插入 1.3 更新 1.4 替换 2. 查找 2.1 select 列 2.2 where 条件 具体案例 2.3 结果排序 总结关键字执行顺序 2.4 筛选分页结果 CRUD : Create(创建)&#xff0c;Retrieve(读取)&…

C语言:代码运行的底层奥秘,编译和链接

目录 翻译环境和运行环境编译环境预编译&#xff08;预处理&#xff09;编译词法分析语法分析语义分析 汇编 链接运行环境 翻译环境和运行环境 在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器…

2024 FinTechathon 校园行:助力高校学生探索金融科技创新

在金融科技蓬勃发展的当下&#xff0c;人才培养成为推动行业前行的关键。为推进深圳市金融科技人才高地建设&#xff0c;向高校学子提供一个展示自身知识、能力和创意的平台&#xff0c;2024 FinTechathon 深圳国际金融科技大赛——西丽湖金融科技大学生挑战赛重磅开启&#xf…

第7章 内容共享

第 7 章 内容共享 bilibili学习地址 github代码地址 本章介绍Android不同应用之间共享内容的具体方式&#xff0c;主要包括&#xff1a;如何利用内容组件在应用之间共享数据&#xff0c;如何使用内容组件获取系统的通讯信息&#xff0c;如何借助文件提供器在应用之间共享文件…

控制台安全内部:创新如何塑造未来的硬件保护

在 Help Net Security 的采访中&#xff0c;安全研究人员 Specter 和 ChendoChap 讨论了游戏机独特的安全模型&#xff0c;并强调了它与其他消费设备的不同之处。 他们还分享了对游戏机安全性的进步将如何影响未来消费者和企业硬件设计的看法。 斯佩克特 (Specter) 是本周在阿…

开源项目-投票管理系统

哈喽&#xff0c;大家好&#xff0c;今天主要给大家带来一个开源项目-投票管理系统 投票管理系统主要有首页&#xff0c;发起投票&#xff0c;管理投票&#xff0c;参与投票&#xff0c;查看投票等功能 首页 为用户提供了一键导航到各个功能模块的便捷途径。 新增投票 用户…