【Unity】在Editor主工具栏中添加自定义UI
在Unity 2021.3中测试。
Unity Editor中的主工具栏是一个 VisualElement
,可以按照常规的UIToolkit使用流程为主工具栏添加自定义UI。
主工具栏分为3部分:
- 左侧UI区域
- 中间PlayMode UI区域
- 右侧UI区域
可以用反射获取到这3个UI元素,然后在其下添加自定义UI:
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
var toolbarObj = toolbarType.GetField("get").GetValue(null);
VisualElement toolbarRoot = (VisualElement)toolbarType.GetField("m_Root",
BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(toolbarObj);
VisualElement toolbarLeft = s_toolbarRoot.Q("ToolbarZoneLeftAlign");
VisualElement toolbarRight = s_toolbarRoot.Q("ToolbarZoneRightAlign");
下面的示例代码向主工具栏中添加了一个设置Time Scale的滑动条。
备注:示例中,Time Scale滑动条右侧的数值输入框中没能正常显示滑动条数值,是由Unity的Bug导致的,详见:https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-40353 。
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UObject = UnityEngine.Object;
[InitializeOnLoad]
public static class CustomEditorToolbar
{
#region Custom Left UI
private static void InitializeCustomLeftUI() {
}
private static void UpdateCustomLeftUI() {
}
#endregion
#region Custom Right UI
private static Slider s_timeScaleSlider;
private static void InitializeCustomRightUI()
{
// Time Scale
s_timeScaleSlider = new Slider("Time Scale", 0f, 2f) // modify the range for your own needs
{
value = Time.timeScale,
// MEMO Unity Bug: https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-40353
// The text won't display
showInputField = true,
style =
{
width = 200,
},
};
s_timeScaleSlider.labelElement.style.minWidth = 0;
s_timeScaleSlider.labelElement.style.flexShrink = 1;
s_timeScaleSlider.RegisterValueChangedCallback(evt =>
{
var timeMgrAsset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TimeManager.asset")[0];
Undo.RecordObject(timeMgrAsset, "Change Time Scale");
Time.timeScale = evt.newValue;
});
s_customToolbarRight.Add(s_timeScaleSlider);
}
private static void UpdateCustomRightUI()
{
// Time Scale
s_timeScaleSlider.SetValueWithoutNotify(Time.timeScale);
}
#endregion
#region Lifecycle
private static VisualElement s_toolbarRoot;
private static VisualElement s_toolbarLeft;
private static VisualElement s_toolbarRight;
private static VisualElement s_customToolbarLeft;
private static VisualElement s_customToolbarRight;
static CustomEditorToolbar()
{
// EditorApplication.delayCall += TryInitialize;
EditorApplication.update -= OnUpdate;
EditorApplication.update += OnUpdate;
}
private static void TryInitialize()
{
if (s_toolbarRoot != null)
{
return;
}
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
var toolbarObj = toolbarType.GetField("get").GetValue(null);
s_toolbarRoot = (VisualElement)toolbarType.GetField("m_Root", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(toolbarObj);
s_toolbarLeft = s_toolbarRoot.Q("ToolbarZoneLeftAlign");
s_toolbarRight = s_toolbarRoot.Q("ToolbarZoneRightAlign");
s_customToolbarLeft = new VisualElement
{
name = "custom-toolbar-left",
style =
{
flexGrow = 1,
flexDirection = FlexDirection.RowReverse,
overflow = Overflow.Hidden,
},
};
s_toolbarLeft.Add(s_customToolbarLeft);
s_customToolbarRight = new VisualElement
{
name = "custom-toolbar-right",
style =
{
flexGrow = 1,
flexDirection = FlexDirection.Row,
overflow = Overflow.Hidden,
},
};
s_toolbarRight.Add(s_customToolbarRight);
InitializeCustomLeftUI();
InitializeCustomRightUI();
}
private static void OnUpdate()
{
TryInitialize();
UpdateCustomLeftUI();
UpdateCustomRightUI();
}
#endregion
}