Unity ugui非常不友好!自定义控件创建流程。

[TOC]

刚接触unity ugui,觉得以下几点非常不友好

  1. 好的工具软件都有顺手的快捷键,为有如此编辑过程才能高效生产。然而!!!万万没想到!Unity居然没有创建控件的快捷键。目前都要从Hierarchy窗口右键->UI,或者菜单GameObject->UI创建控件。
  2. 很多控件不需要勾选raycastTarget。但创建的控件默认勾选raycastTarget。而选了raycastTarget的控件,会额外参与摄像机的UI事件计算。所以为了避免不必要的消耗,我们在每次创建控件后,都要手动关闭该选项。
  3. 各个游戏项目可能使用了各自的非默认字库。但Text默认使用了Arial.ttf字库。所以每次创建后,都要重新选择字库。

有如下几个方法解决上面问题

  1. 查看UnityEditor.UI是否允许设置自定义控件的创建过程
  2. 修改ugui源码。使用它满足我们项目的要求
  3. 覆盖创建控件的菜单命令

创建控件的代码在ui/UnityEditor.UI/UI/MenuOptions.cs1,我详细看了一下,未发现有可以委托创建控件的设定,即方法1不可行。修改源码的做法不够通用,实在办法时再来考虑方法2。而方法3比较容易实现.

定义菜单命令,需要用到UnityEditor.MenuItem特性,举个简单的例子为静态方法添加特性[MenuItem(“Menu1/item1”)],重新编译代码后,会在顶部菜单出现菜单项如下图 再添加字符#&t即可为Menu1/item1菜单命令绑定快捷键shift+alt+t,如[MenuItem("Menu1/item1 #&t")]。如果是#&a,即绑定为shift+alt+a。关于UnityEditor.MenuItem详细说明见官方文档2

英文字符 win按键 mac按键
% CTRL CMD
# Shift Shift
& alt alt

以下是简单创建Image控件示例,它覆盖了Unity原有的菜单命令GameObject/UI/Image并且绑定了快捷键shift+alt+i

[MenuItem("GameObject/UI/Image #&i")]
public static void CreateImage(MenuCommand menuCommand)
{
    GameObject go = new GameObject("Image", typeof(Image));
    go.GetComponent<Image>().raycastTarget = false;

    GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
    Undo.RegisterCreatedObjectUndo(go, "Create " + go.name);
    Selection.activeObject = go;
}

以下是另外一个做法。它复用了UGUI创建控件的原有代码,内部接口会将新创建的控件缓存在全局变量Selection.activeGameObject。当内部方法调用结束后,对Selection.activeGameObject对象稍加调整即可。由于内部接口声明为internal,以下用到了反射进行调用。

private static System.Type type = null;
public static System.Type GetMenuOptionsClass()
{
    if (type == null)
    {
        type = System.Type.GetType("UnityEditor.UI.MenuOptions,UnityEditor.UI");
    }

    return type;
}

private static Dictionary<string, System.Reflection.MethodInfo> dict = null;
public static GameObject Invoke(string funcName, MenuCommand menuCommand)
{
    if (string.IsNullOrEmpty(funcName))
    {
        return null;
    }

    if (!dict.ContainsKey(funcName))
    {
        System.Type type = System.Type.GetType("UnityEditor.UI.MenuOptions,UnityEditor.UI");
        System.Reflection.MethodInfo func = type.GetMethod(funcName);

        if (func != null)
        {
           dict.Add(funcName, func);
        }
        else
        {
            Debug.LogError("找不到方法: " + funcName);
            return null;
        }
    }

    dict[funcName].Invoke(null, new System.Object[] { menuCommand });
    return Selection.activeGameObject;
}

/// <summary>
/// 重写CreateImage,不勾选raycastTarget
/// </summary>
[MenuItem("GameObject/UI/Image")]
public static void CreateImage(MenuCommand menuCommand)
{
    GameObject go = Invoke("AddImage", menuCommand);
    if (go != null)
    {
        go.GetComponent<Image>().raycastTarget = false;
    }
}



原文:
https://lizijie.github.io/2019/05/23/ugui%E9%9D%9E%E5%B8%B8%E4%B8%8D%E5%8F%8B%E5%A5%BD-%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E5%88%9B%E5%BB%BA%E6%B5%81%E7%A8%8B.html
作者github:
https://github.com/lizijie

  1. https://bitbucket.org/Unity-Technologies/ui/src/0651862509331da4e85f519de88c99d0529493a5/UnityEditor.UI/UI/MenuOptions.cs?at=2018.3%2Fstaging 

  2. https://docs.unity3d.com/ScriptReference/MenuItem.html 

PREVIOUSC++不应该有垃圾回收
NEXTUnity3d IL2CPP 内存对齐错误