使用 Unity EditorWindow 提高生产力
使用 Unity EditorWindow 提高生产力
📖 资料
约定
- 实现方式
- 继承于
EditorWindow
类 - 实现
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
方法,并且每次焦点回到这个窗口时,会触发2次OnFocus
方法 - 无权检测输入(
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(); } } }
-
设置当前窗口的位置到当前鼠标位置(也可以进行适当偏移)
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)
,这是必须的,要不然位置不对!