大家好,我是阿赵。这次来分享一下在Unity引擎里面怎样对编辑器的界面进行扩展。
第一篇先分享一下Unity编辑器怎样自定义窗体。
1、简单的创建一个窗体
using UnityEditor;
using UnityEngine;
public class TestEditorWindow : EditorWindow
{
[MenuItem("Tools/TestWindow")]
private static void ShowTestWindow()
{
GetWindow<TestEditorWindow>("测试窗体");
}
void OnGUI()
{
GUILayout.Label("这是一个测试界面");
}
}
加粗样式注意事项
- 编辑器类脚本一定要放到Editor文件夹里面
这个Editor文件夹不一定在Assets/Editor,只需要父级文件夹是Editor就行,可以放在别的文件里面。 - using UnityEditor;
想使用编辑器的API,必须要引用UnityEditor。 - 继承EditorWindow
由于是想显示一个窗体,所以要继承EditorWindow,这样这个类就会有一个窗体的载体和生命周期。 - MenuItem
这是Unity编辑器添加菜单选项的方法。里面的参数是路径,比如刚才的例子
[MenuItem("Tools/TestWindow")]
所以菜单会出现在Unity编辑器的顶部菜单栏,先出现一个Tools的选项,点击进去,会看到二级菜单”TestWindow”。
5. GetWindow
完整的方法名称是EditorWindow.GetWindow(),由于我们这里已经继承了EditorWindow,所以直接用GetWindow也能调用。传入需要获得的窗体的类型,就可以得到一个对应类型的窗体。
如果窗体已经显示了出来,返回的就是当前显示的窗体对象。如果这个窗体没有被创建过,就会创建一个新的对应类型的窗体,并且返回这个窗体的实例对象。
6. OnGUI
需要显示的窗体内容,将会写在OnGUI方法里面。
2、 控制窗体标题和大小
之前通过GetWindow方法,传入了一个标题,其实也可以不传参数,而在后面修改标题,比如这样:
TestEditorWindow win = GetWindow<TestEditorWindow>();
win.titleContent = new GUIContent("测试窗体");
通过titleContent可以指定窗体的标题。
默认的窗体,是没有指定大小的,可以随意的拖动缩放大小。
如果想指定窗体的大小范围,可以:
win.maxSize = new Vector2(600, 600);
win.minSize = new Vector2(400, 400);
这样窗体就可以最大放大到600x600,最小缩小到400x400
如果想指定窗体的大小不想让用户缩放,可以这样:
win.maxSize = win.minSize = new Vector2(600, 600);
这时候窗体被固定在600x600,不能缩放。
3、 窗体方法
EditorWindow一些方法可以使用
1. 打开和关闭窗体
获得窗体之后,可以通过Show方法显示,通过Close方法关闭。
如果是通过单例的形式自己存储了窗体的实例,就可以:
win.Show();
win.Close();
来控制窗体的打开和关闭。或者在界面里面添加关闭按钮,主动调用Close来关闭。
2. 获得焦点
比如同时打开了2个窗体,然后2个窗体的对象存储在一个控制类里面。这时候想某个窗体强制获得焦点,就可以:
win1.Focus();
3. 强制重绘
在某些情况下,窗体可以不会主动的重绘,比如失去了焦点之类的情况。这时候可以通过Repaint方法主动的强制重绘窗体。
void OnInspectorUpdate()
{
Repaint();
}
4. 显示提示
ShowNotification方法可以显示一个比较好看的渐变提示,它会在几秒钟后消失。
比如这样:
ShowNotification(new GUIContent("这是一个提示"));
如果想控制提示的持续时间,可以:
ShowNotification(new GUIContent("这是一个提示"),10);
这里传入了参数10,这个提示会维持10秒钟再消失。
如果想提示不要等10秒,而是立刻消失,可以:
RemoveNotification();
这样提示会立刻消失。
5. 发送和接收事件
通过SendEvent可以向指定的窗体发送事件,比如:
win.SendEvent(EditorGUIUtility.CommandEvent("Paste"));
然后在接收的窗体里面接收:
void OnGUI()
{
Event e = Event.current;
if (e.commandName == "Paste")
Debug.Log("Paste received");
}
6. 窗体里面嵌入窗体
通过BeginWindows和EndWindows,可以往一个窗体里面嵌入另外一个窗体
比如:
public Rect windowRect = new Rect(100, 100, 200, 200);
void OnGUI()
{
BeginWindows();
windowRect = GUILayout.Window(1, windowRect, DoWindow, "Hi There");
EndWindows();
}
void DoWindow(int unusedWindowID)
{
GUILayout.Button("Hi");
GUI.DragWindow();
}
7. 其他
还有其他一些方法,就不一一列举,可以查看Unity的API文档
4、 生命周期
作为EditorWindow,它有一系列的生命周期,具体可看以下代码:
using UnityEditor;
using UnityEngine;
public class TestEditorWindow : EditorWindow
{
[MenuItem("Tools/TestWindow")]
private static void ShowTestWindow()
{
GetWindow<TestEditorWindow>("测试窗体");
}
void OnGUI()
{
GUILayout.Label("这是一个测试界面");
}
/// <summary>
/// 当对象被创建时调用
/// </summary>
private void Awake()
{
Debug.Log("Awake");
}
/// <summary>
/// 当窗体被显示时调用
/// </summary>
private void OnEnable()
{
Debug.Log("OnEnable");
}
/// <summary>
/// 当窗体被隐藏时调用
/// </summary>
private void OnDisable()
{
Debug.Log("OnDisable");
}
/// <summary>
/// 当窗体被销毁时调用
/// </summary>
private void OnDestroy()
{
Debug.Log("OnDestroy");
}
/// <summary>
/// 当窗体获得焦点时调用
/// </summary>
private void OnFocus()
{
Debug.Log("OnFocus");
}
/// <summary>
/// 当窗体失去焦点时调用
/// </summary>
private void OnLostFocus()
{
Debug.Log("OnLostFocus");
}
/// <summary>
/// 当Hierarchy栏有改变时调用
/// </summary>
private void OnHierarchyChange()
{
Debug.Log("OnHierarchyChange");
}
/// <summary>
/// 当项目有改变时调用
/// </summary>
private void OnProjectChange()
{
Debug.Log("OnProjectChange");
}
/// <summary>
/// 当选择的对象改变时调用
/// </summary>
private void OnSelectionChange()
{
Debug.Log("OnSelectionChange");
}
/// <summary>
/// 当Inspector栏有显示时每帧调用
/// </summary>
private void OnInspectorUpdate()
{
Debug.Log("OnInspectorUpdate");
}
/// <summary>
/// 当前窗体在显示的过程中每帧调用
/// </summary>
private void Update()
{
Debug.Log("Update");
}
}
上面的生命周期方法都有备注,应该都很好理解。可以试试运行,打开和关闭界面,进行一些对应的操作,感受一下这些生命周期的调用规律。
需要说明一下的是,OnInspectorUpdate和Update。如果电脑的焦点在Unity编辑器里面时,不管焦点是否在当前窗体,这两个Update方法都是会被调用的。如果电脑的焦点已经不在Unity编辑器里面,OnInspectorUpdate方法不会被调用,但Update方法还是会被调用。
5、 可以使用的UI显示组件
先说结论,Unity的GUI、GUILayout、EditorGUI和EditorGUILayout里面的所有方法,都可以写在EditorWindow的OnGUI里面,方法有很多,可以自己查询一下Unity的API文档:
其中GUI和GUILayout是常规的UnityEditor界面方法,不仅能用于编辑器类,也用于运行时。不过现在基本上运行时大家都会用UGUI之类可视化的UI编辑了,所以GUI和GUILayout会比较多用于编辑器界面扩展。两者的区别是,GUI是需要自己写UI出现的Rect坐标,而GUILayout是可以使用自动布局的。
而EditorGUI和EditorGUILayout是只能用于编辑器类里面的,EditorGUI需要指定Rect坐标,而EditorGUILayout可以自动布局。
GUI系列和EditorGUI系列,有很多重复的方法,不过EditorGUI系列会有更多的功能,这些功能只能在编辑器的界面上显示,比如一些对象的输入、曲线调节、颜色输入、下拉列表之类。