在写 EditorWindow 或者 Inspector 面板时,为了能清晰的表现某些功能或者状态、属性,常常需要用到一些 Unity 引擎中的图标,这时就需要一个能够显示和查找内置图标的功能。

首先看一下效果:

image.png

image.png

Unity 里其实内置了两套尺寸的图标,小图标共 2577 个,同时,由于 Unity 具有两种皮肤,浅色皮肤和深色 Pro 皮肤,因此为了保持更好的可读性,图标也对两种外观进行了适配,深色图标的名称一般是浅色图标的名称加 d_ 开头。

下面针对窗口的不同区域进行拆解。

图标列表

首先拿到所有图标名称的列表,图标列表来自于 GitHub 上的一个用户的整理:

https://gist.github.com/MattRix/c1f7840ae2419d8eb2ec0695448d4321

然后需要排除一些非法图标(比如一些没有图片的图标):

    private void OnEnable()
    {
        var all_icons = ico_list.Where(x => GetIcon(x) != null);
        List<string> unique = new List<string>();
        foreach (Texture2D x in Resources.FindObjectsOfTypeAll<Texture2D>())
        {
            GUIContent icoContent = GetIcon(x.name);
            if (icoContent == null) continue;

            if (!all_icons.Contains(x.name))
            {
                unique.Add(x.name);
            }
        }

        ico_list = ico_list.ToList().Concat(unique).ToArray();
        Resources.UnloadUnusedAssets();
        System.GC.Collect();
    }
    
    GUIContent GetIcon(string icon_name)
    {
        GUIContent valid = null;
        Debug.unityLogger.logEnabled = false;
        if (!string.IsNullOrEmpty(icon_name)) valid = EditorGUIUtility.IconContent(icon_name);
        Debug.unityLogger.logEnabled = true;
        return valid?.image == null ? null : valid;
    }

读取资源后做一次 GC。

准备一下窗口绘制需要用到的样式和数据:

    static GUIContent iconSelected;
    static List<GUIContent> iconContentListAll;
    static List<GUIContent> iconContentListSmall;
    static List<GUIContent> iconContentListBig;
    static List<string> iconMissingNames;
    static GUIStyle iconButtonStyle = null;
    static GUIStyle iconPreviewBlack = null;
    static GUIStyle iconPreviewWhite = null;
    
    void InitIcons()
    {
        if (iconContentListSmall != null) return;

        iconButtonStyle = new GUIStyle(EditorStyles.miniButton);
        iconButtonStyle.margin = new RectOffset(0, 0, 0, 0);
        iconButtonStyle.fixedHeight = 0;

        iconPreviewBlack = new GUIStyle(iconButtonStyle);
        AllTheTEXTURES(ref iconPreviewBlack, Texture2DPixel(new Color(0.15f, 0.15f, 0.15f)));

        iconPreviewWhite = new GUIStyle(iconButtonStyle);
        AllTheTEXTURES(ref iconPreviewWhite, Texture2DPixel(new Color(0.85f, 0.85f, 0.85f)));

        iconMissingNames = new List<string>();
        iconContentListSmall = new List<GUIContent>();
        iconContentListBig = new List<GUIContent>();
        iconContentListAll = new List<GUIContent>();

        for (var i = 0; i < ico_list.Length; ++i)
        {
            GUIContent ico = GetIcon(ico_list[i]);

            if (ico == null)
            {
                iconMissingNames.Add(ico_list[i]);
                continue;
            }

            ico.tooltip = ico_list[i];

            iconContentListAll.Add(ico);

            if (!(ico.image.width <= 36 || ico.image.height <= 36))
                iconContentListBig.Add(ico);
            else iconContentListSmall.Add(ico);
        }
    }
    
    void AllTheTEXTURES(ref GUIStyle s, Texture2D t)
    {
        s.hover.background = s.onHover.background = s.focused.background = s.onFocused.background = s.active.background = s.onActive.background = s.normal.background = s.onNormal.background = t;
        s.hover.scaledBackgrounds = s.onHover.scaledBackgrounds = s.focused.scaledBackgrounds = s.onFocused.scaledBackgrounds = s.active.scaledBackgrounds = s.onActive.scaledBackgrounds = s.normal.scaledBackgrounds = s.onNormal.scaledBackgrounds = new Texture2D[] { t };
    }

搜索区域