在顶部绘制一些功能按钮
代码放在Editor文件夹即可
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace UnityToolbarExtender
{
[InitializeOnLoad]
public static class ToolbarExtender
{
static int m_toolCount;
static GUIStyle m_commandStyle = null;
public static readonly List<Action> LeftToolbarGUI = new List<Action>();
public static readonly List<Action> RightToolbarGUI = new List<Action>();
static ToolbarExtender()
{
Type toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
FieldInfo toolIcons = toolbarType.GetField("s_ShownToolIcons",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
var array = ( Array ) toolIcons.GetValue( null );
m_toolCount = array != null ? array.Length : 6;
ToolbarCallback.OnToolbarGUI -= OnGUI;
ToolbarCallback.OnToolbarGUI += OnGUI;
}
static void OnGUI()
{
// Create two containers, left and right
// Screen is whole toolbar
if (m_commandStyle == null)
{
m_commandStyle = new GUIStyle("CommandLeft");
}
var screenWidth = EditorGUIUtility.currentViewWidth;
// Following calculations match code reflected from Toolbar.OldOnGUI()
float playButtonsPosition = (screenWidth - 100) / 2;
Rect leftRect = new Rect(0, 0, screenWidth, Screen.height);
leftRect.xMin += 10; // Spacing left
leftRect.xMin += 32 * m_toolCount; // Tool buttons
leftRect.xMin += 20; // Spacing between tools and pivot
leftRect.xMin += 64 * 2; // Pivot buttons
leftRect.xMax = playButtonsPosition;
Rect rightRect = new Rect(0, 0, screenWidth, Screen.height);
rightRect.xMin = playButtonsPosition;
rightRect.xMin += m_commandStyle.fixedWidth * 3; // Play buttons
rightRect.xMax = screenWidth;
rightRect.xMax -= 10; // Spacing right
rightRect.xMax -= 80; // Layout
rightRect.xMax -= 10; // Spacing between layout and layers
rightRect.xMax -= 80; // Layers
rightRect.xMax -= 20; // Spacing between layers and account
rightRect.xMax -= 80; // Account
rightRect.xMax -= 10; // Spacing between account and cloud
rightRect.xMax -= 32; // Cloud
rightRect.xMax -= 10; // Spacing between cloud and collab
rightRect.xMax -= 78; // Colab
// Add spacing around existing controls
leftRect.xMin += 10;
leftRect.xMax -= 10;
rightRect.xMin += 10;
rightRect.xMax -= 10;
// Add top and bottom margins
leftRect.y = 5;
leftRect.height = 24;
rightRect.y = 5;
rightRect.height = 24;
if (leftRect.width > 0)
{
GUILayout.BeginArea(leftRect);
GUILayout.BeginHorizontal();
foreach (var handler in LeftToolbarGUI)
{
handler();
}
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
if (rightRect.width > 0)
{
GUILayout.BeginArea(rightRect);
GUILayout.BeginHorizontal();
foreach (var handler in RightToolbarGUI)
{
handler();
}
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}
}
}
using System;
using UnityEngine;
using UnityEditor;
using System.Reflection;
#if UNITY_2019_1_OR_NEWER
using UnityEngine.UIElements;
#else
using UnityEngine.Experimental.UIElements;
#endif
namespace UnityToolbarExtender
{
public static class ToolbarCallback
{
static Type m_toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
static Type m_guiViewType = typeof(Editor).Assembly.GetType("UnityEditor.GUIView");
static PropertyInfo m_viewVisualTree = m_guiViewType.GetProperty("visualTree",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static FieldInfo m_imguiContainerOnGui = typeof(IMGUIContainer).GetField("m_OnGUIHandler",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static ScriptableObject m_currentToolbar;
/// <summary>
/// Callback for toolbar OnGUI method.
/// </summary>
public static Action OnToolbarGUI;
static ToolbarCallback()
{
EditorApplication.update -= OnUpdate;
EditorApplication.update += OnUpdate;
}
static void OnUpdate()
{
// Relying on the fact that toolbar is ScriptableObject and gets deleted when layout changes
if (m_currentToolbar == null)
{
// Find toolbar
var toolbars = Resources.FindObjectsOfTypeAll(m_toolbarType);
m_currentToolbar = toolbars.Length > 0 ? (ScriptableObject) toolbars[0] : null;
if (m_currentToolbar != null)
{
// Get it's visual tree
var visualTree = (VisualElement) m_viewVisualTree.GetValue(m_currentToolbar, null);
// Get first child which 'happens' to be toolbar IMGUIContainer
var container = (IMGUIContainer) visualTree[0];
// (Re)attach handler
var handler = (Action) m_imguiContainerOnGui.GetValue(container);
handler -= OnGUI;
handler += OnGUI;
m_imguiContainerOnGui.SetValue(container, handler);
}
}
}
static void OnGUI()
{
var handler = OnToolbarGUI;
if (handler != null) handler();
}
}
}
使用
using UnityEditor;
using UnityEngine;
using UnityToolbarExtender;
namespace Assets.Editor.Toolbar
{
[InitializeOnLoad]
public static class TestToolbar
{
static TestToolbar()
{
ToolbarExtender.LeftToolbarGUI.Add(OnToolbarGUI);
}
private static void OnToolbarGUI()
{
GUILayout.Space(50);
if (GUILayout.Button("测试按钮"))
{
Debug.LogError("测试成功");
}
GUILayout.FlexibleSpace();
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityToolbarExtender;
namespace EditorUIAlign
{
/// <summary>
/// 对齐方向
/// </summary>
public enum AlignType
{
[Header("顶")]
Top = 1,
[Header("左")]
Left = 2,
[Header("右")]
Right = 3,
[Header("底")]
Bottom = 4,
/// <summary>
/// 水平居中
/// </summary>
[Header("水中")]
HorizontalCenter = 5,
/// <summary>
/// 垂直居中
/// </summary>
[Header("垂中")]
VerticalCenter = 6,
/// <summary>
/// 横向分布
/// </summary>
[Header("水平")]
Horizontal = 7,
/// <summary>
/// 纵向分布
/// </summary>
[Header("垂直")]
Vertical = 8,
}
/// <summary>
/// UI对象对齐功能扩展
/// </summary>
[InitializeOnLoad]
public class UiAlignToolbar
{
static UiAlignToolbar()
{
ToolbarExtender.LeftToolbarGUI.Add(OnToolbarGUI);
}
static void OnToolbarGUI()
{
GUILayout.Space(50);
foreach (var temp in Enum.GetNames(typeof(AlignType)))
{
var type = (AlignType)Enum.Parse(typeof(AlignType), temp);
var desc = EnumItemToDescription(type);
if (GUILayout.Button(desc))
{
Align(type);
}
}
GUILayout.FlexibleSpace();
}
private static string EnumItemToDescription(Enum enumValue)
{
Type enumType = enumValue.GetType();
string optionName = enumValue.ToString();
FieldInfo fieldInfo = enumType.GetField(optionName);
HeaderAttribute[] attributes =
fieldInfo.GetCustomAttributes<HeaderAttribute>(false)
as HeaderAttribute[];
return attributes.Length > 0 ? attributes[0].header : optionName;
}
#region 对齐
public static void Align(AlignType type)
{
List<RectTransform> rects = new List<RectTransform>();
GameObject[] objects = Selection.gameObjects;
if (objects != null && objects.Length > 0)
{
for (int i = 0; i < objects.Length; i++)
{
RectTransform rect = objects[i].GetComponent<RectTransform>();
if (rect != null)
rects.Add(rect);
}
}
if (rects.Count > 1)
{
Align(type, rects);
}
}
public static void Align(AlignType type, List<RectTransform> rects)
{
RectTransform tenplate = rects[0];
float w = tenplate.sizeDelta.x * tenplate.lossyScale.x;
float h = tenplate.sizeDelta.y * tenplate.localScale.y;
float x = tenplate.position.x - tenplate.pivot.x * w;
float y = tenplate.position.y - tenplate.pivot.y * h;
switch (type)
{
case AlignType.Top:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float th = trans.sizeDelta.y * trans.localScale.y;
Vector3 pos = trans.position;
pos.y = y + h - th + trans.pivot.y * th;
trans.position = pos;
}
break;
case AlignType.Left:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float tw = trans.sizeDelta.x * trans.lossyScale.x;
Vector3 pos = trans.position;
pos.x = x + tw * trans.pivot.x;
trans.position = pos;
}
break;
case AlignType.Right:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float tw = trans.sizeDelta.x * trans.lossyScale.x;
Vector3 pos = trans.position;
pos.x = x + w - tw + tw * trans.pivot.x;
trans.position = pos;
}
break;
case AlignType.Bottom:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float th = trans.sizeDelta.y * trans.localScale.y;
Vector3 pos = trans.position;
pos.y = y + th * trans.pivot.y;
trans.position = pos;
}
break;
case AlignType.HorizontalCenter:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float tw = trans.sizeDelta.x * trans.lossyScale.x;
Vector3 pos = trans.position;
pos.x = x + 0.5f * w - 0.5f * tw + tw * trans.pivot.x;
trans.position = pos;
}
break;
case AlignType.VerticalCenter:
for (int i = 1; i < rects.Count; i++)
{
RectTransform trans = rects[i];
float th = trans.sizeDelta.y * trans.localScale.y;
Vector3 pos = trans.position;
pos.y = y + 0.5f * h - 0.5f * th + th * trans.pivot.y;
trans.position = pos;
}
break;
case AlignType.Horizontal:
float minX = GetMinX(rects);
float maxX = GetMaxX(rects);
rects.Sort(SortListRectTransformByX);
float distance = (maxX - minX) / (rects.Count - 1);
for (int i = 1; i < rects.Count - 1; i++)
{
RectTransform trans = rects[i];
Vector3 pos = trans.position;
pos.x = minX + i * distance;
trans.position = pos;
}
break;
case AlignType.Vertical:
float minY = GetMinY(rects);
float maxY = GetMaxY(rects);
rects.Sort(SortListRectTransformByY);
float distanceY = (maxY - minY) / (rects.Count - 1);
for (int i = 1; i < rects.Count - 1; i++)
{
RectTransform trans = rects[i];
Vector3 pos = trans.position;
pos.y = minY + i * distanceY;
trans.position = pos;
}
break;
}
}
private static int SortListRectTransformByX(RectTransform r1, RectTransform r2)
{
float w = r1.sizeDelta.x * r1.lossyScale.x;
float x1 = r1.position.x - r1.pivot.x * w;
w = r2.sizeDelta.x * r2.lossyScale.x;
float x2 = r2.position.x - r2.pivot.x * w;
if (x1 >= x2)
return 1;
else
return -1;
}
private static int SortListRectTransformByY(RectTransform r1, RectTransform r2)
{
float w = r1.sizeDelta.y * r1.lossyScale.y;
float y1 = r1.position.y - r1.pivot.y * w;
w = r2.sizeDelta.y * r2.lossyScale.y;
float y2 = r2.position.y - r2.pivot.y * w;
if (y1 >= y2)
return 1;
else
return -1;
}
private static float GetMinX(List<RectTransform> rects)
{
if (null == rects || rects.Count == 0)
return 0;
RectTransform tenplate = rects[0];
float minx = tenplate.position.x;
float tempX = 0;
for (int i = 1; i < rects.Count; i++)
{
tempX = rects[i].position.x;
if (tempX < minx)
minx = tempX;
}
return minx;
}
private static float GetMaxX(List<RectTransform> rects)
{
if (null == rects || rects.Count == 0)
return 0;
RectTransform tenplate = rects[0];
float maxX = tenplate.position.x;
float tempX = 0;
for (int i = 1; i < rects.Count; i++)
{
tempX = rects[i].position.x;
if (tempX > maxX)
maxX = tempX;
}
return maxX;
}
private static float GetMinY(List<RectTransform> rects)
{
if (null == rects || rects.Count == 0)
return 0;
RectTransform tenplate = rects[0];
float minY = tenplate.position.y;
float tempX = 0;
for (int i = 1; i < rects.Count; i++)
{
tempX = rects[i].position.y;
if (tempX < minY)
minY = tempX;
}
return minY;
}
private static float GetMaxY(List<RectTransform> rects)
{
if (null == rects || rects.Count == 0)
return 0;
RectTransform tenplate = rects[0];
float maxY = tenplate.position.y;
float tempX = 0;
for (int i = 1; i < rects.Count; i++)
{
tempX = rects[i].position.y;
if (tempX > maxY)
maxY = tempX;
}
return maxY;
}
#endregion
}
}