EditorWindow居中显示实现/获取Unity主窗口的区域信息

24 篇文章 1 订阅
1 篇文章 0 订阅

简介

在编辑EditorWindow的时候,某些情况下,我们希望打开的窗口相对于Unity编辑器来说居中显示,一般情况下通过new Rect(0, 0, Screen.currentResolution.width, Screen.currentResolution.height)获得的是主显示器窗口的尺寸,但是如果Unity窗口非全屏或者使用多个显示器做开发,则无法得到正确的位置。

本文将介绍一种通过反射方式可以得到Unity主窗口位置信息的方法,同时也会提供对应的扩展实现以简化将EditorWindow居中显示

声明

本文中的内容属于个人总结整理而来,个人水平有限,对于部分细节难免有理解错误及遗漏之处,如果您在阅读过程中有所发现,希望您能指正,同时文章中的部分内容也参考了其它大神的文章,如果文章中的内容侵犯了您的权益,表示非常歉意,请您指出,我将尽快修改。

如果您进行转载,请标明出处。

Unity技术 EditorWindow居中显示实现/获取Unity主窗口的区域信息(http://www.liyubin.com/articles/2020/11/16/1605527665480.html)

获取Unity主窗口所在的区域信息

  1. 通过反射的方式获取需要的指定类型的所有的子类。

    public static class ReflectionUtility
    {
        public static Type[] GetAllChildClasses(Type baseType, bool allowInvisible = false, bool allowAbstract = false)
        {
            var types = new List<Type>();
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();
            var isSubclass = baseType.IsGenericType
                ? (Func<Type, bool>)
                    ((type) => IsSubclassOfRawGeneric(type,baseType))
                : ((type) => type.IsSubclassOf(baseType));
    
            foreach (var assembly in assemblies)
            {
                foreach (var type in assembly.GetTypes())
                {
                    if (!isSubclass(type) ||(!type.IsVisible&&!allowInvisible) || (!allowAbstract && type.IsAbstract))
                    {
                        continue;
                    }
    
                    types.Add(type);
                }
            }
    
            return types.ToArray();
        }
    }
    

    GetAllChildClasses函数参数说明:

    • baseType:指定的基类
    • allowInvisible:是否获取隐藏的类型(比如使用private,interval修饰的类型)
    • allowAbstract:是否获取虚类型
  2. 通过反射的方式获取Unity主窗口的位置信息

        public static class AppExtension
        {
            private static Rect GetEditorMainWindowPos()
            {
                var containerWinType = ReflectionUtility.GetAllChildClasses(typeof(ScriptableObject),true).Where(t => t.Name == "ContainerWindow").FirstOrDefault();
                if (containerWinType == null)
                    throw new System.MissingMemberException("Can't find internal type ContainerWindow. Maybe something has changed inside Unity");
                var showModeField = containerWinType.GetField("m_ShowMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                var positionProperty = containerWinType.GetProperty("position", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                if (showModeField == null || positionProperty == null)
                    throw new System.MissingFieldException("Can't find internal fields 'm_ShowMode' or 'position'. Maybe something has changed inside Unity");
                var windows = Resources.FindObjectsOfTypeAll(containerWinType);
                foreach (var win in windows)
                {
                    var showmode = (int)showModeField.GetValue(win);
                    if (showmode == 4) // main window
                    {
                        var pos = (Rect)positionProperty.GetValue(win, null);
                        return pos;
                    }
                }
                throw new System.NotSupportedException("Can't find internal main window. Maybe something has changed inside Unity");
            }
        }
    

EditorWindow窗口居中显示

我们使用扩展函数来实现窗口居中。

public static class EditorWindowExtension
{
    public static void CenterOnMainWin(this EditorWindow win)
    {
        var main = AppExtension.GetEditorMainWindowPos();
        var pos = win.position;
        float w = (main.width - pos.width) * 0.5f;
        float h = (main.height - pos.height) * 0.5f;
        pos.x = main.x + w;
        pos.y = main.y + h;
        win.position = pos;
    }
}

使用方式

public class LogViewer : EditorWindow
{
    [MenuItem("Game/Log/Viewer")]
    public static void ShowWin()
    {
        var viewer = GetWindow<LogViewer>();
        viewer.titleContent = new GUIContent("Log Viewer");
        
        viewer.CenterOnMainWin();

        viewer.Show();
    }
}

参考资料

你可以使用以下代码来获取 Unity 窗口的状态: ``` using UnityEngine; using System.Runtime.InteropServices; public class WindowStatus : MonoBehaviour { // 导入 Win32 API [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsZoomed(IntPtr hWnd); // 获取 Unity 窗口的句柄 private IntPtr unityHwnd = IntPtr.Zero; void Start() { unityHwnd = GetUnityWindowHandle(); } void Update() { // 获取窗口最小化状态 bool isMinimized = IsIconic(unityHwnd); // 获取窗口最大化状态 bool isMaximized = IsZoomed(unityHwnd); // 输出窗口状态 Debug.Log("窗口最小化状态:" + isMinimized); Debug.Log("窗口最大化状态:" + isMaximized); } // 获取 Unity 窗口的句柄 private IntPtr GetUnityWindowHandle() { IntPtr hwnd = IntPtr.Zero; // 获取 Unity 窗口的句柄 if (Application.platform == RuntimePlatform.WindowsPlayer) { hwnd = GetForegroundWindow(); } else if (Application.platform == RuntimePlatform.WindowsEditor) { hwnd = GetUnityEditorMainWindowHandle(); } return hwnd; } // 获取当前处于焦点的窗口的句柄 [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); // 获取 Unity 编辑器窗口的句柄 [DllImport("user32.dll")] private static extern IntPtr GetUnityEditorMainWindowHandle(); } ``` 这段代码通过 Win32 API 获取 Unity 窗口的句柄,并调用 IsIconic 和 IsZoomed 函数获取窗口的最小化和最大化状态。请注意,这段代码只能在 Windows 平台上使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值