您当前的位置: 首页 >  unity
  • 4浏览

    0关注

    157博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity UI Toolkit学习笔记-EditorWindow

牙膏上的小苏打2333 发布时间:2022-08-30 17:43:54 ,浏览量:4

🏳‍🌈使用UIToolkit制作EditorWindow
  • 🍨创建
  • 🍡启用编辑器扩展功能
  • 🍰搭建
    • 💡重命名
    • 💡修改排列方式
    • 💡边框颜色
    • 💡代码添加ui元素
  • 🍧交互
  • 🥡USS样式
    • 💡组件类样式控制
    • 💡名称(ID)样式控制
    • 💡StyleClass自定义样式类
    • 💡嵌套样式
    • 💡伪类
  • 🌮UI Toolkit Debugger调试
  • ⏲计时器
  • 🛫复用样式到Inspector面板

🍨创建

新建一个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("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();
        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("right");
            rightVE.Add(helpBox);
            rightVE.Add(helpBox1);
            rightVE.Add(helpBox2);
            rightVE.Add(helpBox3);
        }

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

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

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

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

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

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

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

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

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

    private void OnListViewSelectItemChange(IEnumerable 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();
            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配置文件 在这里插入图片描述 在这里插入图片描述 参考教程 官方文档

关注
打赏
1664520285
查看更多评论
立即登录/注册

微信扫码登录

0.2710s