.wlt文件
Unity编辑器布局文件保存在一个.wlt的文件,目录为 ../Unity/Unity2021.3.11f1/Editor/Data/Resources/Layouts/
我们同样一个可以自己保存一个.wlt文件使用的时候加载。具体方法是通过反射拿到UnityEditor.WindowLayout
,里面有LoadWindowLayout
和SaveWindowLayout
方法,用来加载和保存.wlt布局文件。
using System;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityEditor;
public class LayoutUtility
{
private static readonly MethodInfo s_LoadWindowLayoutMethod;
private static readonly MethodInfo s_SaveWindowLayoutMethod;
static LayoutUtility()
{
var typeWindowLayout = Type.GetType("UnityEditor.WindowLayout,UnityEditor");
if (typeWindowLayout != null)
{
s_LoadWindowLayoutMethod = typeWindowLayout.GetMethod(("LoadWindowLayout"),
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null,
new Type[] {typeof(string), typeof(bool)}, null);
s_SaveWindowLayoutMethod = typeWindowLayout.GetMethod(("SaveWindowLayout"),
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null,
new Type[] {typeof(string)}, null);
}
}
/// <summary>
/// 保存Layout到资源文件
/// </summary>
public static void SaveLayoutToAsset(string assetPath)
{
if (s_SaveWindowLayoutMethod == null)
return;
var path = Path.Combine(Directory.GetCurrentDirectory(), assetPath);
s_SaveWindowLayoutMethod.Invoke(null, new object[] {path});
}
/// <summary>
/// 加载.wlt文件
/// </summary>
public static void LoadLayoutFromAsset(string assetPath)
{
if (s_LoadWindowLayoutMethod == null)
return;
var path = Path.Combine(Directory.GetCurrentDirectory(), assetPath);
s_LoadWindowLayoutMethod.Invoke(null, new object[] {path, false});
}
}
用代码实现窗口停靠
同样通过反射拿到对应的属于和方法将两个界面绑定。
/// <summary>
/// 窗口停靠
/// </summary>
public static void DockEditorWindow(EditorWindow parent, EditorWindow child)
{
var screenPoint = parent.position.min + new Vector2(parent.position.width * .9f, 100f);
Assembly assembly = typeof(UnityEditor.EditorWindow).Assembly;
Type ew = assembly.GetType("UnityEditor.EditorWindow");
Type da = assembly.GetType("UnityEditor.DockArea");
Type sv = assembly.GetType("UnityEditor.SplitView");
FieldInfo tp = ew.GetField("m_Parent", BindingFlags.NonPublic | BindingFlags.Instance);
if (tp == null)
return;
var parentArea = tp.GetValue(parent);
var childArea = tp.GetValue(child);
PropertyInfo tDockAreaParent = da.GetProperty("parent", BindingFlags.Public | BindingFlags.Instance);
if (tDockAreaParent == null)
return;
var oView = tDockAreaParent.GetValue(parentArea, null);
MethodInfo tDragOver = sv.GetMethod("DragOver", BindingFlags.Public | BindingFlags.Instance);
if(tDragOver == null)
return;
var oDropInfo = tDragOver.Invoke(oView, new object[] { child, screenPoint });
FieldInfo tDockArea = da.GetField("s_OriginalDragSource", BindingFlags.NonPublic | BindingFlags.Static);
if(tDockArea == null)
return;
tDockArea.SetValue(null, childArea);
MethodInfo tPerformDrop = sv.GetMethod("PerformDrop", BindingFlags.Public | BindingFlags.Instance);
if (tPerformDrop == null)
return;
tPerformDrop.Invoke(oView, new object[] { child, oDropInfo, null });
}
创建多窗口
主窗体
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
public class MainWindow : EditorWindow
{
private const string LAYOUT_INFO_PATH = "Assets/Editor/Examples/LayoutInfo/layout.wlt";
private static MainWindow mainWindow;
private static SubWindow1 subWindow1;
private static SubWindow2 subWindow2;
private void OnEnable()
{
var toolbar = new Toolbar();
var btn1 = new Button(() => { LayoutUtility.LoadLayoutFromAsset(LAYOUT_INFO_PATH); }) {text = "加载布局"};
toolbar.Add(btn1);
var btn2 = new Button(() =>
{
LayoutUtility.SaveLayoutToAsset(LAYOUT_INFO_PATH);
AssetDatabase.Refresh();
}) {text = "保存布局"};
toolbar.Add(btn2);
rootVisualElement.Add(toolbar);
}
[MenuItem("Tool/多窗口显示")]
public static void Open()
{
mainWindow = GetWindow<MainWindow>("MainWindow");
mainWindow.Init();
mainWindow.Show();
}
private void Init()
{
subWindow1 = SubWindow1.Open();
subWindow2 = SubWindow2.Open();
LoadLayoutByCode();
}
private async void LoadLayoutByCode()
{
await Task.Delay(10);
LayoutUtility.DockEditorWindow(mainWindow, subWindow1);
await Task.Delay(10);
LayoutUtility.DockEditorWindow(mainWindow, subWindow2);
}
}
子窗体1
using UnityEditor;
public class SubWindow1 : EditorWindow
{
public static SubWindow1 Open()
{
var window = GetWindow<SubWindow1>("SubWindow1");
window.Show();
return window;
}
}
子窗体2
using UnityEditor;
public class SubWindow2 : EditorWindow
{
public static SubWindow2 Open()
{
var window = GetWindow<SubWindow2>("SubWindow2");
window.Show();
return window;
}
}
在打开的时候用代码实现吸附,值得注意是需要在所有窗体完全打开的情况下才能吸附。只能用协程做下延迟。
private async void LoadLayoutByCode()
{
await Task.Delay(10);
LayoutUtility.DockEditorWindow(mainWindow, subWindow1);
await Task.Delay(10);
LayoutUtility.DockEditorWindow(mainWindow, subWindow2);
}
效果展示
默认打开的界面
调整布局后保存,点击加载布局的界面
参考
UnityToolchainsTrick - 15.EditorWindow代码停靠与合并
Comments NOTHING