Unity Toolbar工具栏扩展

# 效果图

 

using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
#if UNITY_2019_1_OR_NEWER
using UnityEngine.UIElements;
#else
using UnityEngine.Experimental.UIElements;
#endif

[InitializeOnLoad]
public class ToolbarExtend
{
    static ScriptableObject _toolbar;
    static int _toolIconCount; //左侧的: 抓手, 移动, 旋转等那几个工具

    static GUIStyle _commandStyle;

    static ToolbarExtend()
    {
        EditorApplication.update -= OnEditorUpdate;
        EditorApplication.update += OnEditorUpdate;
    }

    static void OnEditorUpdate()
    {
        if (null != _toolbar) return;

        Type Type_Toolbar = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
        InitToolIconCount(Type_Toolbar);
        RegToolbarOnGUI(Type_Toolbar);
    }

    static void InitToolIconCount(Type Type_Toolbar)
    {
#if UNITY_2019_1_OR_NEWER
        string fieldName = "k_ToolCount";
#else
        string fieldName = "s_ShownToolIcons";
#endif
        var ToolBar_s_ShowToolIcons = Type_Toolbar.GetField(fieldName,
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); //Toolbar.s_ShownToolIcons
#if UNITY_2019_1_OR_NEWER
        _toolIconCount = ToolBar_s_ShowToolIcons != null ? ((int) ToolBar_s_ShowToolIcons.GetValue(null)) : 7;
#elif UNITY_2018_1_OR_NEWER
        _toolIconCount = ToolBar_s_ShowToolIcons != null ? ((Array) ToolBar_s_ShowToolIcons.GetValue(null)).Length : 6;
#else
        _toolIconCount = ToolBar_s_ShowToolIcons != null ? ((Array) ToolBar_s_ShowToolIcons.GetValue(null)).Length : 5;
#endif
    }

    //注册Toolbar的OnGUIHandler的监听
    static void RegToolbarOnGUI(Type Type_Toolbar)
    {
        // Find toolbar
        var toolbars = Resources.FindObjectsOfTypeAll(Type_Toolbar);
        _toolbar = toolbars.Length > 0 ? (ScriptableObject) toolbars[0] : null;
        if (null == _toolbar) return;

        Type Type_GUIView = typeof(Editor).Assembly.GetType("UnityEditor.GUIView");
        PropertyInfo GUIView_visualTree = Type_GUIView.GetProperty("visualTree",
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        //toolbar上可放置ui的容器, 我们这边放在第1个容器
        var visualTree = (VisualElement) GUIView_visualTree.GetValue(_toolbar, null);
        var container = (IMGUIContainer) visualTree[0];

        //监听OnGUI
        FieldInfo IMGUIContainer_m_OnGUIHandler = typeof(IMGUIContainer).GetField("m_OnGUIHandler",
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        var handler = (Action) IMGUIContainer_m_OnGUIHandler.GetValue(container);
        handler -= Toolbar_OnGUI;
        handler += Toolbar_OnGUI;
        IMGUIContainer_m_OnGUIHandler.SetValue(container, handler);
    }
    
    //Toolbar的OnGUI
    static void Toolbar_OnGUI()
    {
        var screenWidth = EditorGUIUtility.currentViewWidth;

        // Following calculations match code reflected from Toolbar.OldOnGUI()
        float playButtonX = (screenWidth - 100) / 2;
        
        OnGUI_ToolbarLeft(screenWidth, playButtonX);
        OnGUI_ToolbarRight(screenWidth, playButtonX);
    }

    static void OnGUI_ToolbarLeft(float screenWidth, float playButtonX)
    {
        Rect leftRect = new Rect(0, 0, screenWidth, Screen.height);
        leftRect.xMin += 10; // Spacing left
        leftRect.xMin += 32 * _toolIconCount; // Tool buttons
        leftRect.xMin += 20; // Spacing between tools and pivot
        leftRect.xMin += 64 * 2; // Pivot/Center, Local/World
        leftRect.xMax = playButtonX;

        // Add spacing around existing controls
        leftRect.xMin += 10;
        leftRect.xMax -= 10;
        // Add top and bottom margins
        leftRect.y = 7;
        leftRect.height = 24;

        if (leftRect.width > 0)
        {
            GUILayout.BeginArea(leftRect);
            GUILayout.BeginHorizontal();

            //********** 在这边绘制自定义ui
            GUILayout.FlexibleSpace();
            GUILayout.Label("Toolbar左侧");
            GUILayout.TextField("", GUILayout.Width(100));
            if (GUILayout.Button("测试按钮"))
            {

            }
            //**********

            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }
    }

    static void OnGUI_ToolbarRight(float screenWidth, float playButtonX)
    {
        if (_commandStyle == null)
            _commandStyle = new GUIStyle("CommandLeft");

        Rect rightRect = new Rect(0, 0, screenWidth, Screen.height);
        rightRect.xMin = playButtonX;
        rightRect.xMin += _commandStyle.fixedWidth * 3; // Play buttons
        rightRect.xMax = screenWidth;
        rightRect.xMax -= 10; // Spacing right
        rightRect.xMax -= 80; // Layout
        rightRect.xMax -= 10; // Spacing between layout and layers
        rightRect.xMax -= 80; // Layers
        rightRect.xMax -= 20; // Spacing between layers and account
        rightRect.xMax -= 80; // Account
        rightRect.xMax -= 10; // Spacing between account and cloud
        rightRect.xMax -= 32; // Cloud
        rightRect.xMax -= 10; // Spacing between cloud and collab
        rightRect.xMax -= 78; // Colab

        // Add spacing around existing controls
        rightRect.xMin += 10;
        rightRect.xMax -= 10;
        // Add top and bottom margins
        rightRect.y = 5;
        rightRect.height = 24;

        if (rightRect.width > 0)
        {
            GUILayout.BeginArea(rightRect);
            GUILayout.BeginHorizontal();

            //********** 在这边绘制自定义ui
            GUILayout.FlexibleSpace();
            GUILayout.Label("Toolbar右侧");
            GUILayout.TextField("", GUILayout.Width(100));
            if (GUILayout.Button("测试按钮"))
            {

            }
            //**********

            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }
    }

}

# Toolbar的刷新

static void RepaintToolbar()
{
    MethodInfo Tools_RepaintAllToolViews = typeof(Tools).GetMethod("RepaintAllToolViews",BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
    Tools_RepaintAllToolViews.Invoke(null,null);
}

# 注意:下面的代码无法刷新Toolbar

static void RepaintToolbar2()
{
    SceneView.RepaintAll();
    
    MethodInfo GameView_RepaintAll = typeof(Editor).Assembly.GetType("UnityEditor.GameView").GetMethod("RepaintAll");
    GameView_RepaintAll.Invoke(null, null);
}

 

【参考】

Unity编辑器拓展之自定义UnityToolbar_素颜悠悠的博客-CSDN博客,这个讲的很全

Unity3D研究院编辑器之脚本设置ToolBar(二十三) | 雨松MOMO程序研究院 (xuanyusong.com)

Unity编辑器拓展之三十:拓展UnityToolBar | JingFengJi

posted @ 2022-03-23 23:02  yanghui01  阅读(724)  评论(0编辑  收藏  举报