使用 Unity EditorWindow 提高生产力

使用 Unity EditorWindow 提高生产力

📖 资料

约定

  • 实现方式
    1. 继承于EditorWindow
    2. 实现OnGUI方法
      • 可以使用GUILayout / GUI / EditorGUILayout类来绘制各种你想要的 字段 / 按钮
  • 打开方式
    • 通过菜单栏打开
      使用MenuItem在方法里面实例化/创建一个窗口并打开
    • 通过代码打开
  • 创建 / 实例化 一个窗口
    // 创建一个窗口
    var wCreate = CreateWindow<UniversalBgWindow>();
    
    // 实例化一个窗口
    var wIns = CreateInstance<UniversalBgWindow>();
    
    // 获取指定类型的窗口(如果当前场景中没有这个类型的窗口 ,会自动创建一个)
    var wGet = GetWindow<UniversalBgWindow>();
    
    // GetWindow Source Code
        public static T GetWindow<T>(string title, bool focus, params Type[] desiredDockNextTo) where T : EditorWindow
            {
                T[] array = Resources.FindObjectsOfTypeAll(typeof(T)) as T[];
                T val = ((array.Length != 0) ? array[0] : null);
                if ((UnityEngine.Object)val != (UnityEngine.Object)null)
                {
                    if (focus)
                    {
                        val.Focus();
                    }
    
                    return val;
                }
    
                return CreateWindow<T>(title, desiredDockNextTo);
            }
    
  • 显示窗口
    • Show()方法
      • 显示窗口
      • 如果窗口已经显示,则会将其置于顶层
    • ShowWindowAsDp(rect,size)
    • ......

神器

  • 获取当前焦点所在的窗口
    var windowFocus = EditorWindow.focusedWindow;
    
  • 获取鼠标所在的窗口
    var windowMouseOver = EditorWindow.mouseOverWindow;
    
    • ⚠️ 当以ShowPopup方式显示一个窗口时,mouseOverWindow会返回null
  • 获取所有打开的窗口
      var windowsOpened = Resources.FindObjectsOfTypeAll<EditorWindow>();
    

非正常现象

  • 当显示一个EditorWindow时,就会立即触发它的OnFocus方法,并且每次焦点回到这个窗口时,会触发2OnFocus方法
  • 无权检测输入(Input)事件,这意味着:
    • 你无法在特定的的窗口中,使用特定快捷键来差异化来提高生产力并且避免快捷键冲突
    • 你甚至无法使用Esc 关闭当前窗口 😭
    • 你也不可以使用Enter确认/提交 某些操作
    • ......
  • 无法实现透明窗口,比如:

    当需要显示一些零散的选项在鼠标周围时,有几个选项就创建几个窗口,而不是直接在一个EditorWindow中直接创建这些选项

    就像下图这样
  • 不允许设置窗口的具体尺寸,只能通过minSize / maxSize来设置窗口的最大/最小尺寸

    public void ShowAsDropDown(Rect buttonRect, Vector2 windowSize)
    除非使用ShowAsDropDown来显示窗口,否则无法设置窗口的具体尺寸
  • 想要获取当前鼠标所在的位置,只能去OnGUI()中获取,在OnEnable()中不行,这意味着当你想创建一个窗口时,就设置好他的位置时,大多时候不尽人意
    • Event.current会因为返回空,而导致获取Event.current.mousePosition时报错!!!
    • Input.mousePosition会直接返回Vector3(0,0,0)

🧑‍🍳 🛠️

  • 使用快捷键 Ctrl + W 来关闭当前窗口,顺便忽略一些系统必须的窗口

        /// <summary>
        /// 关闭窗口时,忽略以下系统必须的窗口
        /// </summary>
        public static string[] ignoreWindowsName = new string[] { "Scene", "Game", "Project", "Hierarchy", "Inspector", "Console" };
    
    
        /// <summary>
        /// 关闭当前焦点所在的窗口(但<see cref="ignoreWindowsName"/>中的窗口不受影响)
        /// </summary>
        [MenuItem("Window/Close/关闭当前焦点所在的窗口 %_W")]
        public static void CloseTheWindowCurrentFocus()
        {
            var window = EditorWindow.focusedWindow;
            bool CanClose = ignoreWindowsName.Where((string name) => { return window.titleContent.text == name; }).Count() == 0;
            if (CanClose)
            {
                Log.LogAtUnityEditor($"关闭当前焦点所在的窗口:{window.name} : [{window.titleContent.text}]", "#00ff00");
                window.Close();
            }
        }
    
  • 使用快捷键 Ctrl + Shift + W 来关闭所有非必须的窗口,顺便忽略一些系统必须的窗口

    /// <summary>
    /// 关闭所有非必须的窗口(但<see cref="ignoreWindowsName"/>中的窗口不受影响)
    /// </summary>
    [MenuItem("Window/Close/关闭所有非必须的窗口 %#_W")]
    public static void CloseAllWindowsButNecessary()
    {
        var windows = Resources.FindObjectsOfTypeAll<EditorWindow>();
        foreach (var window in windows)
        {
            bool CanClose = ignoreWindowsName.Where((string name) => { return window.titleContent.text == name; }).Count() == 0;
            if (CanClose)
            {
                Log.LogAtUnityEditor($"关闭窗口:{window.name} : [{window.titleContent.text}]", "#00ff00");
                window.Close();
            }
        }
    
    }
    
    
    
    
  • 设置当前窗口的位置到当前鼠标位置(也可以进行适当偏移)

    在OnGUI中获取当前鼠标位置

    public bool bHavInitPos = false;
    
    private void OnGUI()
    {
      // 设置窗口位置到鼠标位置
      if (!bHavInitPos)
      {
          Vector2 mousePos = Event.current.mousePosition;
          var mousePosOnScreen = GUIUtility.ScreenToGUIPoint(mousePos);
          position = new Rect(mousePosOnScreen.x, mousePosOnScreen.y, position.width, position.height);
    
          bHavInitPos = true;
          Log.LogAtUnityEditor($"mousePos:{mousePos}   mousePosOnScreen:{mousePosOnScreen}");
      }
    
      // Render ...
    }
    
    

    ⚠️GUIUtility.GUIToScreenPoint(Event.current.mousePos),这是必须的,要不然位置不对!

posted @ 2023-07-20 16:58  清风0307  阅读(176)  评论(0编辑  收藏  举报