0


Unity UI Toolkit拓展编辑器

1、项目初始化,导入UI Builder

1.1 导入UI Builder

Unity版本2020及以上才支持,2020版本需要打开preview,才能使用

1.2 创建编辑器面板

2、使用UI Builder搭建面板结构

2.1 参数设置修改的样式

3、在代码中使用控件,使用ObjectField和ListView

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;

public class TestWindow : EditorWindow
{
    private ObjectField objectField;

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

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

        // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/TestWindow.uxml");
        VisualElement labelFromUXML = visualTree.Instantiate();
        labelFromUXML.style.flexGrow = 1;
        root.Add(labelFromUXML);

        //获取控件
        objectField = root.Q<ObjectField>("ObjectField");
        //设置控件参数
        objectField.objectType = typeof(GameObject);

    }
}
        //获取控件
        listView = root.Q<ListView>("ListView");
        //listView组件单个item组件创建方法绑定
        listView.makeItem = MakeListItem;
        //listView组件单个item绑定数据
        listView.bindItem = BindListItem;
        //listView组件选中item改变事件
        listView.onSelectionChange += OnSelectItem;

    private void OnSelectItem(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            GameObject go = item as GameObject;
            Selection.activeObject = item as GameObject;
            /*
            //nameText.value = go.name;
            //posText.value = go.transform.localPosition;
            
            SerializedObject so = new SerializedObject(go);
            nameText.Bind(so);

            SerializedObject so2 = new SerializedObject(go.transform);
            posText.Bind(so2);
            */

            if(go.TryGetComponent<MyCube>(out comp))
            {
                var so = new SerializedObject(comp);
                tempField.Bind(so);
            }
            else
            {
                tempField.Unbind();
            }

        }
    }

    private void BindListItem(VisualElement ve, int index)
    {
        Label label = ve as Label;
        var go = sceneObjects[index];
        label.text = go.name;
    }

    private VisualElement MakeListItem()
    {
        var label = new Label();
        label.style.unityTextAlign = TextAnchor.MiddleLeft;
        label.style.paddingLeft = 5;
        return label;
    }

4、数据绑定、事件监听

        //数据绑定
        nameText = root.Q<TextField>("NameText");
        posText = root.Q<Vector3Field>("PosText");
        nameText.bindingPath = "m_Name";
        posText.bindingPath = "m_LocalPosition";

        tempField = root.Q<IntegerField>("TempField");
        tempField.bindingPath = "Temp";

        //事件监听
        tempTextField = root.Q<TextField>("TempTextField");
        tempTextField.RegisterValueChangedCallback<string>(OnTempTextFieldValueChange);

    private void OnSelectItem(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            GameObject go = item as GameObject;
            Selection.activeObject = item as GameObject;
            /*
            //nameText.value = go.name;
            //posText.value = go.transform.localPosition;
            
            SerializedObject so = new SerializedObject(go);
            nameText.Bind(so);

            SerializedObject so2 = new SerializedObject(go.transform);
            posText.Bind(so2);
            */

            if(go.TryGetComponent<MyCube>(out comp))
            {
                var so = new SerializedObject(comp);
                tempField.Bind(so);
            }
            else
            {
                tempField.Unbind();
            }

        }
    }

    private void OnTempTextFieldValueChange(ChangeEvent<string> evt)
    {
         Debug.Log($"Old: {evt.previousValue},_____ New: {evt.newValue}");
    }

5、USS样式、Debug调试

5.1 USS样式

5.2 Debug调试

6、UI复用到Inspect面板

6.1 将内容创建为创建为VisualElement子类

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

public class SceneObjectPanel : VisualElement
{
    private GameObject[] sceneObjects;
    private ObjectField objectField;
    private Button createBtn;
    private Button refreshBtn;

    private ListView listView;
    private TextField nameText;
    private Vector3Field posText;

    public SceneObjectPanel()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = this;

        // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/SceneObjectWindow.uxml");
        //VisualElement labelFromUXML = visualTree.Instantiate();
        //labelFromUXML.style.flexGrow = 1;
        //root.Add(labelFromUXML);

        visualTree.CloneTree(root);

        var helpBox = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.None);
        var helpBox2 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Info);
        var helpBox3 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Warning);
        var helpBox4 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Error);

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

        objectField = root.Q<ObjectField>("ObjectField");
        objectField.objectType = typeof(GameObject);
        objectField.allowSceneObjects = false;

        createBtn = root.Q<Button>("CreateBtn");
        createBtn.clicked += OnCreateGameObject;

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

        listView = root.Q<ListView>("ListView");
        listView.makeItem = MakeListItem;
        listView.bindItem = BindListItem;
        listView.onSelectionChange += OnSelectItem;

        nameText = root.Q<TextField>("NameText");
        posText = root.Q<Vector3Field>("PosText");
        nameText.bindingPath = "m_Name";
        posText.bindingPath = "m_LocalPosition";

        tempField = root.Q<IntegerField>("TempField");
        tempField.bindingPath = "Temp";

        tempTextField = root.Q<TextField>("TempTextField");
        tempTextField.RegisterValueChangedCallback<string>(OnTempTextFieldValueChange);

        var containter = new IMGUIContainer(CreateIMGUI);
        rightVE.Add(containter);

        //var scheduleItem = this.schedule.Execute(ScheduleAction);
        //scheduleItem.Every(2000);

    }

    private void ScheduleAction(TimerState state)
    {
        Debug.Log("this is a schedule action...");
    }

    private void CreateIMGUI()
    {
        if (GUILayout.Button("IMGUI Button"))
        {
            Debug.Log("this is a imgui button");
        }

    }

    private void OnTempTextFieldValueChange(ChangeEvent<string> evt)
    {
        Debug.Log($"Old: {evt.previousValue},_____ New: {evt.newValue}");
    }

    private MyCube comp;
    private IntegerField tempField;
    private TextField tempTextField;
    private void OnSelectItem(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            GameObject go = item as GameObject;
            Selection.activeObject = item as GameObject;
            /*
            //nameText.value = go.name;
            //posText.value = go.transform.localPosition;
            
            SerializedObject so = new SerializedObject(go);
            nameText.Bind(so);

            SerializedObject so2 = new SerializedObject(go.transform);
            posText.Bind(so2);
            */

            if (go.TryGetComponent<MyCube>(out comp))
            {
                var so = new SerializedObject(comp);
                tempField.Bind(so);
            }
            else
            {
                tempField.Unbind();
            }

        }
    }

    private void BindListItem(VisualElement ve, int index)
    {
        Label label = ve as Label;
        var go = sceneObjects[index];
        label.text = go.name;
    }

    private VisualElement MakeListItem()
    {
        var label = new Label();
        label.style.unityTextAlign = TextAnchor.MiddleLeft;
        label.style.paddingLeft = 5;
        return label;
    }

    private void OnRefresh()
    {
        Scene scene = SceneManager.GetActiveScene();
        sceneObjects = scene.GetRootGameObjects();
        listView.itemsSource = sceneObjects;
    }

    private void OnCreateGameObject()
    {
        GameObject prefab = objectField.value as GameObject;
        var go = GameObject.Instantiate(prefab);

        go.transform.position = new Vector3(Random.Range(-1.0f, 1.0f), 0, Random.Range(-1, 1));
    }
}

6.2 创建子类并使用

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

[CustomEditor(typeof(MyCube))]
public class MyCubeInspector : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        //var root = new VisualElement();
        //root.Add(base.CreateInspectorGUI());
        //var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/SceneObjectWindow.uxml");
        //VisualElement labelFromUXML = visualTree.Instantiate();
        //labelFromUXML.style.flexGrow = 1;
        //root.Add(labelFromUXML);

        //var bas = base.CreateInspectorGUI();
        //root.Add(bas);
        var root = new VisualElement();
        root.Add(new IMGUIContainer(OnInspectorGUI));
        root.Add(new SceneObjectPanel());

        return root;
    }
}

7、完整代码

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

public class SceneObjectWindow : EditorWindow
{
    private GameObject[] sceneObjects;
    private ObjectField objectField;
    private Button createBtn;
    private Button refreshBtn;

    private ListView listView;
    private TextField nameText;
    private Vector3Field posText;

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

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

        // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/SceneObjectWindow.uxml");
        //VisualElement labelFromUXML = visualTree.Instantiate();
        //labelFromUXML.style.flexGrow = 1;
        //root.Add(labelFromUXML);

        visualTree.CloneTree(root);

        var helpBox = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.None);
        var helpBox2 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Info);
        var helpBox3 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Warning);
        var helpBox4 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Error);

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

        objectField = root.Q<ObjectField>("ObjectField");
        objectField.objectType = typeof(GameObject);
        objectField.allowSceneObjects = false;

        createBtn = root.Q<Button>("CreateBtn");
        createBtn.clicked += OnCreateGameObject;

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

        //获取控件
        listView = root.Q<ListView>("ListView");
        //listView组件单个item组件创建方法绑定
        listView.makeItem = MakeListItem;
        //listView组件单个item绑定数据
        listView.bindItem = BindListItem;
        //listView组件选中item改变事件
        listView.onSelectionChange += OnSelectItem;

        //数据绑定
        nameText = root.Q<TextField>("NameText");
        posText = root.Q<Vector3Field>("PosText");
        nameText.bindingPath = "m_Name";
        posText.bindingPath = "m_LocalPosition";

        tempField = root.Q<IntegerField>("TempField");
        tempField.bindingPath = "Temp";

        //事件监听
        tempTextField = root.Q<TextField>("TempTextField");
        tempTextField.RegisterValueChangedCallback<string>(OnTempTextFieldValueChange);

        var containter = new IMGUIContainer(CreateIMGUI);
        rightVE.Add(containter);

        var scheduleItem = rootVisualElement.schedule.Execute(ScheduleAction);
        scheduleItem.Every(2000);
        
    }

    private void ScheduleAction(TimerState state)
    {
        Debug.Log("this is a schedule action...");
    }

    private void CreateIMGUI()
    {
        if(GUILayout.Button("IMGUI Button"))
        {
            Debug.Log("this is a imgui button");
        }

    }

    private void OnTempTextFieldValueChange(ChangeEvent<string> evt)
    {
        Debug.Log($"Old: {evt.previousValue},_____ New: {evt.newValue}");
    }

    private MyCube comp;
    private IntegerField tempField;
    private TextField tempTextField;
    private void OnSelectItem(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            GameObject go = item as GameObject;
            Selection.activeObject = item as GameObject;
            /*
            //nameText.value = go.name;
            //posText.value = go.transform.localPosition;
            
            SerializedObject so = new SerializedObject(go);
            nameText.Bind(so);

            SerializedObject so2 = new SerializedObject(go.transform);
            posText.Bind(so2);
            */

            if(go.TryGetComponent<MyCube>(out comp))
            {
                var so = new SerializedObject(comp);
                tempField.Bind(so);
            }
            else
            {
                tempField.Unbind();
            }

        }
    }

    private void BindListItem(VisualElement ve, int index)
    {
        Label label = ve as Label;
        var go = sceneObjects[index];
        label.text = go.name;
    }

    private VisualElement MakeListItem()
    {
        var label = new Label();
        label.style.unityTextAlign = TextAnchor.MiddleLeft;
        label.style.paddingLeft = 5;
        return label;
    }

    private void OnRefresh()
    {
        Scene scene = SceneManager.GetActiveScene();
        sceneObjects = scene.GetRootGameObjects();
        listView.itemsSource = sceneObjects;
    }

    private void OnCreateGameObject()
    {
        GameObject prefab = objectField.value as GameObject;
        var go = GameObject.Instantiate(prefab);

        go.transform.position = new Vector3(Random.Range(-1.0f, 1.0f), 0, Random.Range(-1, 1));
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyCube : MonoBehaviour
{
    public int Temp;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor.UIElements;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;

public class SceneObjectPanel : VisualElement
{
    private GameObject[] sceneObjects;
    private ObjectField objectField;
    private Button createBtn;
    private Button refreshBtn;

    private ListView listView;
    private TextField nameText;
    private Vector3Field posText;

    public SceneObjectPanel()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = this;

        // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/SceneObjectWindow.uxml");
        //VisualElement labelFromUXML = visualTree.Instantiate();
        //labelFromUXML.style.flexGrow = 1;
        //root.Add(labelFromUXML);

        visualTree.CloneTree(root);

        var helpBox = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.None);
        var helpBox2 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Info);
        var helpBox3 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Warning);
        var helpBox4 = new HelpBox("同学们坐下,这只是一个演示!", HelpBoxMessageType.Error);

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

        objectField = root.Q<ObjectField>("ObjectField");
        objectField.objectType = typeof(GameObject);
        objectField.allowSceneObjects = false;

        createBtn = root.Q<Button>("CreateBtn");
        createBtn.clicked += OnCreateGameObject;

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

        listView = root.Q<ListView>("ListView");
        listView.makeItem = MakeListItem;
        listView.bindItem = BindListItem;
        listView.onSelectionChange += OnSelectItem;

        nameText = root.Q<TextField>("NameText");
        posText = root.Q<Vector3Field>("PosText");
        nameText.bindingPath = "m_Name";
        posText.bindingPath = "m_LocalPosition";

        tempField = root.Q<IntegerField>("TempField");
        tempField.bindingPath = "Temp";

        tempTextField = root.Q<TextField>("TempTextField");
        tempTextField.RegisterValueChangedCallback<string>(OnTempTextFieldValueChange);

        var containter = new IMGUIContainer(CreateIMGUI);
        rightVE.Add(containter);

        //var scheduleItem = this.schedule.Execute(ScheduleAction);
        //scheduleItem.Every(2000);

    }

    private void ScheduleAction(TimerState state)
    {
        Debug.Log("this is a schedule action...");
    }

    private void CreateIMGUI()
    {
        if (GUILayout.Button("IMGUI Button"))
        {
            Debug.Log("this is a imgui button");
        }

    }

    private void OnTempTextFieldValueChange(ChangeEvent<string> evt)
    {
        Debug.Log($"Old: {evt.previousValue},_____ New: {evt.newValue}");
    }

    private MyCube comp;
    private IntegerField tempField;
    private TextField tempTextField;
    private void OnSelectItem(IEnumerable<object> obj)
    {
        foreach (var item in obj)
        {
            GameObject go = item as GameObject;
            Selection.activeObject = item as GameObject;
            /*
            //nameText.value = go.name;
            //posText.value = go.transform.localPosition;
            
            SerializedObject so = new SerializedObject(go);
            nameText.Bind(so);

            SerializedObject so2 = new SerializedObject(go.transform);
            posText.Bind(so2);
            */

            if (go.TryGetComponent<MyCube>(out comp))
            {
                var so = new SerializedObject(comp);
                tempField.Bind(so);
            }
            else
            {
                tempField.Unbind();
            }

        }
    }

    private void BindListItem(VisualElement ve, int index)
    {
        Label label = ve as Label;
        var go = sceneObjects[index];
        label.text = go.name;
    }

    private VisualElement MakeListItem()
    {
        var label = new Label();
        label.style.unityTextAlign = TextAnchor.MiddleLeft;
        label.style.paddingLeft = 5;
        return label;
    }

    private void OnRefresh()
    {
        Scene scene = SceneManager.GetActiveScene();
        sceneObjects = scene.GetRootGameObjects();
        listView.itemsSource = sceneObjects;
    }

    private void OnCreateGameObject()
    {
        GameObject prefab = objectField.value as GameObject;
        var go = GameObject.Instantiate(prefab);

        go.transform.position = new Vector3(Random.Range(-1.0f, 1.0f), 0, Random.Range(-1, 1));
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

[CustomEditor(typeof(MyCube))]
public class MyCubeInspector : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        //var root = new VisualElement();
        //root.Add(base.CreateInspectorGUI());
        //var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/UIToolKit/Editor/SceneObjectWindow.uxml");
        //VisualElement labelFromUXML = visualTree.Instantiate();
        //labelFromUXML.style.flexGrow = 1;
        //root.Add(labelFromUXML);

        //var bas = base.CreateInspectorGUI();
        //root.Add(bas);
        var root = new VisualElement();
        root.Add(new IMGUIContainer(OnInspectorGUI));
        root.Add(new SceneObjectPanel());

        return root;
    }
}
标签: unity 编辑器

本文转载自: https://blog.csdn.net/zhoutao2333/article/details/135915275
版权归原作者 为你写首诗ge 所有, 如有侵权,请联系我们删除。

“Unity UI Toolkit拓展编辑器”的评论:

还没有评论