Unity UI Toolkit学习笔记-EditorWindow

24 篇文章 1 订阅
12 篇文章 4 订阅

🍨创建

新建一个Editor 文件夹用于存放生成的脚本。
在这里插入图片描述
在这里插入图片描述

🍡启用编辑器扩展功能

启用后库里会导入只有在Editor下才能用的组件
在这里插入图片描述
在这里插入图片描述

🍰搭建

双击UXML文件即可打开编辑器进行编辑界面
在这里插入图片描述
也可以用代码的方式创建界面
在这里插入图片描述

💡重命名

一般添加了新的ui元素后尽量重新命名下,方便后续的使用,重命名后物体名称都会自动添加#符号。
请添加图片描述

💡修改排列方式

VisualElement相当于空物体,可以用来组织ui层级结构。可以修改Flex > Direction 改变子ui的排列方式。
请添加图片描述

💡边框颜色

默认是黑色,但需要挪到其它颜色重新选择黑色才起作用!
在这里插入图片描述

在这里插入图片描述

💡代码添加ui元素

public void CreateGUI()
{
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

        // Instantiate UXML
        m_VisualTreeAsset.CloneTree(root);

        var helpBox = new HelpBox("www",HelpBoxMessageType.None);
        var helpBox1 = new HelpBox("www",HelpBoxMessageType.Info);
        var helpBox2 = new HelpBox("www",HelpBoxMessageType.Warning);
        var helpBox3 = new HelpBox("www",HelpBoxMessageType.Error);
		
		//查找已有的ui节点,把代码创建的元素加入到该ui节点下。
        var rightVE = root.Q<VisualElement>("right"); 
        rightVE.Add(helpBox);
        rightVE.Add(helpBox1);
        rightVE.Add(helpBox2);
        rightVE.Add(helpBox3);
}

通过代码添加的ui元素不会显示到UI Builder中,需要打开窗体查看
在这里插入图片描述

窗体位置可以通过脚本获知
在这里插入图片描述
在这里插入图片描述

🍧交互

通过监听ui相关事件进行交互逻辑处理。
在这里插入图片描述

using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

public class SceneObjWindow : EditorWindow
{
    [SerializeField]
    private VisualTreeAsset m_VisualTreeAsset = default;
    private ObjectField objectField;
    private Button creatBtn;
    private Button refreshBtn;
    private ListView listView;
    private GameObject[] sceneObjs;
    private TextField selectItemName;
    private Vector3Field selectLocalPos;
    private IntegerField count;
    private TextField changeTest;

    [MenuItem("Window/UI Toolkit/SceneObjWindow")]
    public static void ShowExample()
    {
        SceneObjWindow wnd = GetWindow<SceneObjWindow>();
        wnd.titleContent = new GUIContent("SceneObjWindow");
    }

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;


        // Instantiate UXML
        m_VisualTreeAsset.CloneTree(root);

        //代码添加ui
        {
            var helpBox = new HelpBox("www", HelpBoxMessageType.None);
            var helpBox1 = new HelpBox("www", HelpBoxMessageType.Info);
            var helpBox2 = new HelpBox("www", HelpBoxMessageType.Warning);
            var helpBox3 = new HelpBox("www", HelpBoxMessageType.Error);

            var rightVE = root.Q<VisualElement>("right");
            rightVE.Add(helpBox);
            rightVE.Add(helpBox1);
            rightVE.Add(helpBox2);
            rightVE.Add(helpBox3);
        }

        //设置ObjectField的过滤
        {
            objectField = root.Q<ObjectField>("ObjectField");
            objectField.objectType = typeof(GameObject);
            objectField.allowSceneObjects = false;
        }

        //监听按钮点击事件
        {
            creatBtn = root.Q<Button>("CreatBtn");
            creatBtn.clicked += OnCreateGo;

            refreshBtn = root.Q<Button>("RefreshBtn");
            refreshBtn.clicked += OnRefresh;
        }

        //ListView动态添加item
        {
            listView = root.Q<ListView>("listView");
            listView.makeItem = MakeListViewItem;
            listView.bindItem = BindListViewItem;
            //监听item选中事件
            listView.onSelectionChange += OnListViewSelectItemChange;
        }

        //数据绑定:始终与组件上的字段值保持同步
        {
            selectItemName = root.Q<TextField>("Name");
            selectItemName.bindingPath = "m_Name";

            selectLocalPos = root.Q<Vector3Field>("LocalPosition");
            selectLocalPos.bindingPath = "m_LocalPosition";

            count = root.Q<IntegerField>("Count");
            count.bindingPath = "count";
        }

        //数据监听:数据发生改变就会触发回调,能取到改变前后的值
        {
            changeTest = root.Q<TextField>("ChangeTest");
            changeTest.RegisterValueChangedCallback(OnValueChange);
        }
    }

    private void OnValueChange(ChangeEvent<string> evt)
    {
        Debug.Log($"pre:{evt.previousValue},new:{evt.newValue}");
    }

    private void OnListViewSelectItemChange(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            var go = item as GameObject;
            selectItemName.value = go.name;
            selectLocalPos.value = go.transform.localPosition;
            Selection.activeGameObject = go;

            //数据绑定
            {
                SerializedObject so = new SerializedObject(go);
                selectItemName.Bind(so);
                SerializedObject so1 = new SerializedObject(go.transform);
                selectLocalPos.Bind(so1);
            }

            var cube = go.GetComponent<MyCube>();
            if (cube != null)
            {
                var so2 = new SerializedObject(cube);
                count.Bind(so2);
                count.visible = true;
            }
            else
            {
                count.Unbind();
                count.visible = false;
            }
        }
    }

    private void BindListViewItem(VisualElement ve, int index)
    {
        Label label = ve as Label;
        var go = sceneObjs[index];
        label.text = go.name;
        SerializedObject so = new SerializedObject(go);
        label.Bind(so);
    }

    private VisualElement MakeListViewItem()
    {
        var label = new Label();
        label.style.unityTextAlign = TextAnchor.MiddleLeft;
        label.style.marginLeft = 5;
        label.bindingPath = "m_Name";
        return label;
    }

    private void OnRefresh()
    {
        sceneObjs = SceneManager.GetActiveScene().GetRootGameObjects();

        //更新ListView
        listView.itemsSource = sceneObjs;
        Debug.Log($"场景物体:{sceneObjs.Length}个");
        listView.RefreshItems();
    }

    private void OnCreateGo()
    {
        var prefab = objectField.value as GameObject;

        if (prefab == null)
        {
            Debug.LogError("ObjectField不能为空!");
            return;
        }
        var go = GameObject.Instantiate(prefab);
        go.transform.position = new Vector3(Random.Range(-5, 5), Random.Range(-5, 5), Random.Range(-5, 5));
    }
}


🥡USS样式

在这里插入图片描述

💡组件类样式控制

直接添加对应于库中的组件名称即可对所有该类型的组件进行样式控制,如图所示对Label字体进行统一的颜色和大小设置。
在这里插入图片描述

请添加图片描述

💡名称(ID)样式控制

通过指定ui的id(#xxx)进行样式的控制,可以进行精准的控制
在这里插入图片描述
请添加图片描述

💡StyleClass自定义样式类

.xxx即表示一个自定义的样式类,
在这里插入图片描述

配置好后可以拖拽到ui上进行应用
请添加图片描述

或者在ui上添加样式。
请添加图片描述
在这里插入图片描述

💡嵌套样式

可以通过 > 定义应用了左边样式的ui子节点样式
在这里插入图片描述

请添加图片描述

💡伪类

伪类缩小了选择器的范围,因此它只匹配进入特定状态的元素。
将伪类附加到简单的选择器以匹配处于特定状态的特定元素。例如,以下 USS 规则使用 :hover 伪类在用户将指针悬停在 Button 元素上时更改其颜色。
在这里插入图片描述

请添加图片描述

🌮UI Toolkit Debugger调试

有些时候使用了选择器却无法起作用
在这里插入图片描述
可以在相应的窗体上打开UI Toolkit Debugger进行排除
在这里插入图片描述
使用Pick Element 功能进行快速定位
请添加图片描述
可以看到除了.MyStyleClass > Label 外还有其它的,可以看下其它的样式是不是做了设置
在这里插入图片描述
可以看到其它的样式中定义了最小宽度135,
在这里插入图片描述
所以宽度无法修改到50,可以覆盖最小宽度为小于50的值
在这里插入图片描述

⏲计时器

var scheduleItem =rootVisualElement.schedule.Execute(ScheduleAction);
//延迟两秒执行
scheduleItem.ExecuteLater(2000);

🛫复用样式到Inspector面板

新建自定义Inspector脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;

[CustomEditor(typeof(MyCube))]
public class MyCubeInspector : Editor
{
    [SerializeField]
    private VisualTreeAsset m_VisualTreeAsset = default;
    public override VisualElement CreateInspectorGUI()
    {
        VisualElement root = new VisualElement();
        m_VisualTreeAsset.CloneTree(root);

        return root;
    }
}

指定m_VisualTreeAsset为新建的UXML配置文件
在这里插入图片描述
在这里插入图片描述
参考教程
官方文档

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牙膏上的小苏打2333

哟,哟,切克闹,煎饼果子来一套

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值