菜单 MenuItem
MenuItem修饰可以让我们对菜单进行扩展,同时,该修饰多数用在静态方法上,CONTEXT除外。
格式:
public MenuItem(string itemName, bool isValidateFunction, int priority)
参数含义:
- itemName:菜单路径,以 “/” 分隔。如"Window/MyFunc",表示将菜单添加到 Window 下的 MyFunc。
- 可以为其添加快捷键:%(ctrl), #(shift), &(alt),例如Ctrl+D:“Window/MyFunc %d”。特殊键位为:LEFT, RIGHT, UP, DOWN, F1 … F12, HOME, END, PGUP, PGDN,可以参考unity api 文档
- GameObject 对应 Hierarchy 窗口右键菜单
- Asset/Create 对应 Project 窗口右键菜单
- CONTEXT/ComponentName/XXX,为选中的Object的Inspector窗口上的ComponentName(可以是系统的如Transform,也可以是我们派生的MonoBehaviour)添加齿轮菜单项。该菜单项需要MenuCommand参数
- isValidateFunction:为true表示该方法是对菜单是否可用的定义。意味着菜单定义由2个方法构成,一个定义逻辑,一个定义是否可用。
- priority:菜单显示优先级,定义在菜单中显示的位置。
其它相关:
- 如果菜单路径与现有一样,则覆盖。
- MenuCommand: 根据需要,可能要用到该参数
- Selection.activeObject: 选中的Object对象,可以是GameObject,也可以是Project中的资源
- Selection.activeGameObject: 选中的GameObject对象
- Selection.activeTransform: 选中的Transform
- Undo.RegisterCreateObjectUndo: 如果创建了对象,注册撤销,以响应界面的撤销操作
- GameObjectUtility.SetParentAndAlign: 创建GameObject时,调用该接口以保证新的GameObject的正确的父子关系。
- EditorUtility.DisplayCustomMenu : 显示自定义菜单
例子:
public class MenuExtend
{
/// <summary>
/// % Ctrl # Shift & Alt
/// </summary>
[MenuItem("My/Test1 %#&a", false, 1)]
static void Test1()
{
Debug.Log("select menu test1.");
}
/// <summary>
/// 在Test1前显示
/// </summary>
[MenuItem("My/Test0", false, 0)]
static void Test0() { }
/// <summary>
/// 该菜单项由下面的函数定义是否可用
/// </summary>
[MenuItem("My/Test/A")]
static void TestA() { }
/// <summary>
/// 选择了一个 GameObject 才可用
/// </summary>
/// <returns></returns>
[MenuItem("My/Test/A", true, 20)]
static bool AValidation()
{
return Selection.activeGameObject != null;
}
/// <summary>
/// 可选中选中菜单
/// </summary>
[MenuItem("My/Test2", false, 3)]
static void Test3()
{
bool chk = Menu.GetChecked("My/Test2");
Menu.SetChecked("My/Test2", !chk);
}
/// <summary>
/// 为 Rigigbody 添加 "Double Mass" 菜单功能
/// </summary>
/// <param name="command"></param>
[MenuItem("CONTEXT/Rigidbody/Double Mass")]
static void DoubleMass(MenuCommand command)
{
Rigidbody body = (Rigidbody)command.context;
body.mass = body.mass * 2;
Debug.Log("Doubled Rigidbody's Mass to " + body.mass + " from Context Menu.");
}
// Add a menu item to create custom GameObjects.
// Priority 1 ensures it is grouped with the other menu items of the same kind
// and propagated to the hierarchy dropdown and hierarchy context menus.
[MenuItem("GameObject/MyCategory/Custom Game Object", false, 10)]
static void CreateCustomGameObject(MenuCommand menuCommand)
{
// Create a custom game object
GameObject go = new GameObject("Custom Game Object");
// Ensure it gets reparented if this was a context click (otherwise does nothing)
GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
// Register the creation in the undo system
Undo.RegisterCreatedObjectUndo(go, "Create " + go.name);
Selection.activeObject = go;
}
}
可以在我们想要的地方显示自定义菜单。比如在 SceneView 中,右键显示我们的菜单:
public class ShowMenuInScene
{
[InitializeOnLoadMethod]
static void Initialize()
{
SceneView.duringSceneGui += OnSceneGUI;
}
static void OnSceneGUI(SceneView sv)
{
if(Event.current != null && Event.current.button == 1 && Event.current.type == EventType.MouseUp)
{
Vector2 pos = Event.current.mousePosition;
GUIContent[] menu = new GUIContent[]
{
new GUIContent("Test0"),
new GUIContent("Test1"),
new GUIContent("Test2"),
new GUIContent(""),
new GUIContent("Test/2")
};
int selected = -1;
object userData = Selection.activeGameObject;
int width = 100;
int height = 100;
Rect rect = new Rect(pos.x, pos.y - height, width, height);
EditorUtility.DisplayCustomMenu(rect, menu, selected, SelectMyMenu, userData);
Event.current.Use();
}
}
static void SelectMyMenu(object data, string[] opt, int select)
{
Debug.Log($"Select my menu:{opt[select]}.");
}
}