Unity编辑器界面扩展——2、Unity编辑器内置资源和风格

  大家好,我是阿赵,继续分享Unity编辑器界面扩展。
  这一篇会举一些编辑器UI的具体例子,然后分享一下怎样使用Unity编辑器内置的资源和风格。

一、 自定义窗体综合小例子

  之前一篇简单了介绍了怎样创建一个自定义的编辑器窗体,介绍了一些EditorWindow的基础知识,这里写一个小例子:

using UnityEditor;
using UnityEngine;
public class TestEditorWindow : EditorWindow
{
    [MenuItem("Tools/TestWindow")]
    private static void ShowTestWindow()
    {
        TestEditorWindow win = GetWindow<TestEditorWindow>();
        win.titleContent = new GUIContent("测试窗体");
        win.maxSize = win.minSize = new Vector2(500, 550);
    }
    private string[] platformList = new string[] { "d_BuildSettings.Switch", "d_BuildSettings.PS5", "d_BuildSettings.XboxOne", "d_BuildSettings.Metro", "d_BuildSettings.iPhone", "d_BuildSettings.Android" };
    private Vector2 platformScrollPos = new Vector2();
    private int iconSize = 100;
    private string filePathStr = "";
    private string searchStr = "";
    private Color selectedColor = Color.white;
    private Object selectedObj;
    private string[] popupStrs = new string[] {"选项一","选项二","选项三","选项四" };
    private int popupIndex = 0;
    void OnGUI()
    {
        GUILayout.Box(EditorGUIUtility.IconContent("azhaoLogo"), GUILayout.Width(512), GUILayout.Height(128));
        GUILayout.BeginHorizontal(EditorStyles.helpBox,GUILayout.Width(500));
        GUILayout.Label("请选择文件路径:", EditorStyles.whiteLargeLabel, GUILayout.Width(100));
        filePathStr = EditorGUILayout.TextField(filePathStr, GUILayout.Width(300), GUILayout.Height(30));
        if (GUILayout.Button(EditorGUIUtility.IconContent("d_OpenedFolder Icon"), GUILayout.Width(40), GUILayout.Height(30)))
        {

        }
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
        GUILayout.Label("请搜索:", EditorStyles.linkLabel, GUILayout.Width(100));
        searchStr = EditorGUILayout.TextField(searchStr, EditorStyles.toolbarSearchField, GUILayout.Width(300));
        GUILayout.EndHorizontal();
        GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(500));
        EditorGUILayout.HelpBox("请问您习惯在哪个平台上玩游戏:",MessageType.Info);
        platformScrollPos = GUILayout.BeginScrollView(platformScrollPos,GUILayout.Height(120));
        GUILayout.BeginHorizontal();
        
        for (int i = 0;i<platformList.Length;i++)
        {
            if(GUILayout.Button(EditorGUIUtility.IconContent(platformList[i]),GUILayout.Width(iconSize),GUILayout.Height(iconSize)))
            {
                //do something
            }
        }
        
        GUILayout.EndHorizontal();
        GUILayout.EndScrollView();
        GUILayout.EndVertical();
        EditorGUILayout.HelpBox("请不要说谎,我知道你在想什么", MessageType.Error);
        GUILayout.BeginHorizontal();
        GUILayout.Label("请选择物体:", EditorStyles.largeLabel, GUILayout.Width(100));
        selectedObj = EditorGUILayout.ObjectField(selectedObj, typeof(Object), true, GUILayout.Width(200));
        GUILayout.EndHorizontal();
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        GUILayout.Label("请选择颜色:", EditorStyles.linkLabel, GUILayout.Width(100));
        selectedColor = EditorGUILayout.ColorField(selectedColor, GUILayout.Width(200));
        GUILayout.EndHorizontal();
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        GUILayout.Label("下拉列表:", GUILayout.Width(100));
        popupIndex = EditorGUILayout.Popup(popupIndex, popupStrs, GUILayout.Width(200));
        GUILayout.EndHorizontal();
    }

}

  运行窗体,会发现现在的窗体是这样的:
在这里插入图片描述

  这个窗体比较简单,但里面用到了一些Unity编辑器扩展里面特有的东西,比如内置图标、自定义图片、编辑器UI风格和特殊组件。

二、 Unity内置图标

1、内置图标的使用

  在上面的例子里面,出现了很多图标,比如各个游戏平台的图标、文件夹的图标和自定义的”阿赵Unity工具”的标题图片。这些图标是怎样调用的呢?
  从代码上看,是通过了

EditorGUIUtility.IconContent

  这个API来获得对应的图标图片的,传入图片的名字,不需要带扩展名,就可以获得相应的图片。
  这个方法,是通过读取Assets/Editor Default Resources/Icons这个路径来获得对应的图片的。这个Editor Default Resources文件夹,在项目里面是看不到的,我们可以自己在Assets文件夹下面建立这个文件夹,然后把图片放到里面。比如我的那个”阿赵Unity工具”标题图片,就是放在这个文件夹里面的。
在这里插入图片描述

  但有很多图片并不需要自己放到这个Assets/Editor Default Resources/Icons文件夹里面,也同样获取得到,比如平台图标"d_BuildSettings.Switch"或者文件夹图标"d_OpenedFolder Icon"。这是因为,Unity编辑器已经内置了一些可以使用的自带的图标,我们可以直接使用的。

2、 获取所有能用的内置图片名称

  既然Unity有很多默认的图标可以使用,那我们怎么知道这些图标的名字呢?比如刚才说的"d_BuildSettings.Switch",是怎么知道的呢?
  这里我做了个工具,可以获取所有的内置图标,并且点击的时候,会打印图标的名称并且复制到剪切板:
在这里插入图片描述

还可以搜索自己想要的关键词:
在这里插入图片描述

  这些内置的资源是怎样获取的呢?
  在网上很多人介绍,说通过Resrouces来获取,比如这样

Texture[] textures = Resources.FindObjectsOfTypeAll<Texture>();

  这种方法可以获取一部分的图标,但很多图标是获取不到的,看看Resources.FindObjectsOfTypeAll的API说明:

在这里插入图片描述

  这个方法只会获取Unity编辑器已经加载了的资源,这会导致一个问题,有一些图标明明能用,但由于没有在Unity编辑器打开过对应的界面显示出来,就获取不到。所以这个方法其实是不行的
  那么真正能获取到所有的icon的名称呢?首先,我们要知道这些资源是存在在哪里的。
先找到Unity的安装目录,然后找到Editor/Data/Resources/unity editor resources文件
在这里插入图片描述

  这个文件里面就有我们需要的资源和名称了。
  这个文件我们打开看会很混乱,不过我们的目的不是完全解析这个文件,而只是想提取出里面的资源名称而已,所以接下来我会用正则表达式来获取。
  首先要知道里面代表资源的表达方式是什么,根据我的观察,里面的资源有2种声明方式:
第1种:
icons/xxxx.png
第2种:
icons/processed/xxxx.asset
  其中xxxx就是图标的名称。
  于是可以分别通过2个正则表达式来匹配:

(?<=icons/)[^\.]+(?=.png)
(?<=icons/processed/)[^\.]+(?=.asset)

  把这些匹配到的名字,保存到一个txt里面,这样就一劳永逸了。我这里随便先保存到了Editor文件夹里面。
  接下来的事情就简单了,通过API

EditorGUIUtility.IconContent

  我们把之前收集到的icon名字列表逐个获取一下,就能把所有的icon获取到了。

三、 Unity内置风格

  在上面的例子里面,用到了一些特殊的UI显示风格,一般是通过EditorStyles来指定的。
  EditorStyles有多少种,不需要我们去猜,因为API上面有写,各位可以自己去查一下:
在这里插入图片描述

  不过API上面的文字是不形象的,也没有附上效果说明,所以我们不知道具体的显示效果。
  于是我也做了个预览工具:
在这里插入图片描述

在这里插入图片描述

同样也是可以通过搜索来找到自己想要的内容。

四、 完整工具源码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;

public class BuiltInResViewTool : EditorWindow
{
    [MenuItem("Tools/显示内置资源")]
    static void ShowWin()
    {
        BuiltInResViewTool _instance = GetWindow<BuiltInResViewTool>("Unity内置资源");
        _instance.minSize = _instance.maxSize = new Vector2(800, 600);
    }
    #region icon
    private string unityEditorResourcesPath = "";
    private List<GUIContent> iconContentList;
    private List<GUIContent> showIconContentList;
    private Vector2 iconScrollPosition = Vector2.zero;
    private int iconSize = 40;
    private int rowCount = 18;
    private string iconFilterStr = "";
    private int builtInIconListExist = -1;
    #endregion

    #region style
    private List<GUIStyle> guiStyles;
    private Vector2 stylesScrollPosition = Vector2.zero;
    private string styleFilterStr = "";
    private List<GUIStyle> showGuiStyleList;
    #endregion
    private int titleSelectIndex = 0;
    private string[] titleStrs = new string[] { "图标", "Style" };
    
    

    
    private void OnGUI()
    {
        titleSelectIndex = GUILayout.SelectionGrid(titleSelectIndex, titleStrs, 2, GUILayout.Width(200));
        if(titleSelectIndex == 0)
        {
            DrawIcons();
        }
        else if(titleSelectIndex == 1)
        {
            DrawStyle();
        }
    }
    #region icon

    /// <summary>
    /// 绘制Icon列表
    /// </summary>
    private void DrawIcons()
    {
        ShowLine("内置Icon");
        GUIStyle style = new GUIStyle();
        style.normal.textColor = Color.yellow;
        
        GUILayout.BeginVertical(EditorStyles.helpBox);
        GUILayout.Label("如果没有显示icon,请找到Unity的安装目录,并选择Editor/Data/Resources/unity editor resources文件", style);
        GUILayout.BeginHorizontal();
        GUILayout.Label("unity editor resources文件:", GUILayout.Width(160));
        EditorGUILayout.TextField(unityEditorResourcesPath, GUILayout.Width(450));
        if (GUILayout.Button(EditorGUIUtility.IconContent("d_OpenedFolder Icon"), EditorStyles.miniButtonMid, GUILayout.Width(40)))
        {
            unityEditorResourcesPath = EditorUtility.OpenFilePanel("请选择Unity安装目录的Editor/Data/Resources/unity editor resources文件", unityEditorResourcesPath, "");
        }
        if (string.IsNullOrEmpty(unityEditorResourcesPath) == false)
        {
            if (GUILayout.Button("生成", GUILayout.Width(80)))
            {
                CreateBuiltInIconList();
            }
        }
        GUILayout.EndHorizontal();
        GUILayout.EndVertical();

        if (builtInIconListExist < 0)
        {
            CheckBuiltInIconList();
        }

        if (builtInIconListExist == 0)
        {
            GUILayout.Label("请先选择unity editor resources文件路径,并生成");
            return;
        }

        if (iconContentList == null)
        {
            GetAllIcons();
        }

        GUILayout.BeginHorizontal();
        GUILayout.Label("搜索:", GUILayout.Width(60));
        EditorGUI.BeginChangeCheck();
        iconFilterStr = EditorGUILayout.TextField(iconFilterStr, EditorStyles.toolbarSearchField, GUILayout.Width(300));
        if (GUILayout.Button("刷新", GUILayout.Width(80)))
        {
            GetAllIcons();
        }

        if (showIconContentList != null)
        {
            GUILayout.Label("找到:" + showIconContentList.Count + "个");
        }
        GUILayout.EndHorizontal();
        if (EditorGUI.EndChangeCheck())
        {
            FilterIconList();
        }
        if (showIconContentList == null || showIconContentList.Count == 0)
        {
            GUILayout.Label("没有找到图标");
            return;
        }

        iconScrollPosition = GUILayout.BeginScrollView(iconScrollPosition);
        GUILayout.BeginHorizontal();
        for (int i = 0; i < showIconContentList.Count; i++)
        {
            if (GUILayout.Button(showIconContentList[i], GUILayout.Width(iconSize), GUILayout.Height(iconSize)))
            {
                string iconName = showIconContentList[i].image.name;
                CopyValue(iconName);
                Debug.Log(iconName + "    已复制到剪切板");
            }
            if (i != 0 && (i + 1) % rowCount == 0)
            {
                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();
            }
        }
        GUILayout.EndHorizontal();
        GUILayout.EndScrollView();
    }

    /// <summary>
    /// 通过搜索过滤内置icon的显示列表
    /// </summary>
    private void FilterIconList()
    {
        showIconContentList = new List<GUIContent>();
        if (iconContentList != null && iconContentList.Count > 0)
        {
            string tempStr = iconFilterStr.ToLower();
            bool needAdd = false;
            for (int i = 0; i < iconContentList.Count; i++)
            {
                if (string.IsNullOrEmpty(tempStr))
                {
                    needAdd = true;
                }
                else
                {
                    if (iconContentList[i].image.name.ToLower().Contains(tempStr))
                    {
                        needAdd = true;
                    }
                    else
                    {
                        needAdd = false;
                    }
                }
                if (needAdd)
                {
                    showIconContentList.Add(iconContentList[i]);
                }
            }
        }
    }
    /// <summary>
    /// 检查内置icon名字列表是否已经生成
    /// </summary>
    private void CheckBuiltInIconList()
    {
        string path = GetIconListPath();
        if (System.IO.File.Exists(path))
        {
            builtInIconListExist = 1;
        }
        else
        {
            builtInIconListExist = 0;
        }
    }
    /// <summary>
    /// 通过unity editor resource生成内置icon名字列表文件
    /// </summary>
    private void CreateBuiltInIconList()
    {
        if(string.IsNullOrEmpty(unityEditorResourcesPath))
        {
            return;
        }
        string content = ReadFileText(unityEditorResourcesPath);
        if (string.IsNullOrEmpty(content))
        {
            Debug.LogError("读取失败:"+unityEditorResourcesPath);
            builtInIconListExist = 0;
            return;
        }
        List<string> iconList = new List<string>();
        string regexStr = @"(?<=icons/)[^\.]+(?=.png)";
        string[] matches = GetAllMatchs(content, regexStr);
        if (matches != null && matches.Length > 0)
        {
            string tempStr;
            for (int i = 0; i < matches.Length; i++)
            {
                tempStr = matches[i].Trim();
                if (iconList.IndexOf(tempStr) < 0)
                {
                    iconList.Add(tempStr);
                }
            }
        }
        regexStr = @"(?<=icons/processed/)[^\.]+(?=.asset)";
        matches = GetAllMatchs(content, regexStr);
        if (matches != null && matches.Length > 0)
        {
            string tempStr;
            for (int i = 0; i < matches.Length; i++)
            {
                tempStr = matches[i].Trim();
                if (iconList.IndexOf(tempStr) < 0)
                {
                    iconList.Add(tempStr);
                }
            }
        }
        string saveContent = "";
        if (iconList.Count > 0)
        {
            for (int i = 0; i < iconList.Count; i++)
            {
                saveContent += iconList[i];
                if (i < iconList.Count - 1)
                {
                    saveContent += "\n";
                }
            }
        }
        string savePath = GetIconListPath();
        CheckFileSavePath(savePath);
        System.IO.File.WriteAllText(savePath, saveContent, System.Text.Encoding.Default);
        builtInIconListExist = 1;
        GetAllIcons();
    }
    /// <summary>
    /// 从内置icon名字列表读取所有可用的icon
    /// </summary>
    private void GetAllIcons()
    {
        iconContentList = new List<GUIContent>();
        string path = GetIconListPath();
        string content = ReadFileText(path);
        if (string.IsNullOrEmpty(content))
        {
            return;
        }
        string[] lines = content.Split('\n');
        for (int i = 0; i < lines.Length; i++)
        {
            GUIContent icon = EditorGUIUtility.IconContent(lines[i].Trim());
            if (icon != null && icon.image != null)
            {
                iconContentList.Add(icon);
            }
        }

        FilterIconList();
    }

    /// <summary>
    /// 获取内置icon名字列表的文件路径
    /// </summary>
    /// <returns></returns>
    private string GetIconListPath()
    {
        return Application.dataPath + "/Editor/builtinIconList.txt";
    }

    #endregion

    #region style

    /// <summary>
    /// 绘制风格列表
    /// </summary>
    private void DrawStyle()
    {
        ShowLine("内置Style");
        if (guiStyles == null)
        {
            GetAllEditorStyles();
        }
        GUILayout.BeginHorizontal();
        GUILayout.Label("搜索:", GUILayout.Width(60));
        EditorGUI.BeginChangeCheck();
        styleFilterStr = EditorGUILayout.TextField(styleFilterStr, EditorStyles.toolbarSearchField, GUILayout.Width(300));
        if (GUILayout.Button("刷新", GUILayout.Width(80)))
        {
            GetAllEditorStyles();
        }
        GUILayout.EndHorizontal();
        if (EditorGUI.EndChangeCheck())
        {
            FilterStyleList();
        }
        if (showGuiStyleList == null || showGuiStyleList.Count == 0)
        {
            GUILayout.Label("没有找到Style");
            return;
        }
        stylesScrollPosition = GUILayout.BeginScrollView(stylesScrollPosition);
        for (int i = 0; i < showGuiStyleList.Count; i++)
        {
            GUILayout.BeginHorizontal();
            EditorGUILayout.TextField(showGuiStyleList[i].name, GUILayout.Width(200));
            GUILayout.Label("样例:", GUILayout.Width(80));
            GUILayout.Label("这是一个测试的范例", showGuiStyleList[i], GUILayout.Width(400));
            GUILayout.EndHorizontal();
            if (i < showGuiStyleList.Count - 1)
            {
                ShowLine("", 750);
            }
        }
        GUILayout.EndScrollView();
    }

    /// <summary>
    /// 通过搜索过滤风格列表
    /// </summary>
    private void FilterStyleList()
    {
        showGuiStyleList = new List<GUIStyle>();
        if (guiStyles != null && guiStyles.Count > 0)
        {
            string tempStr = styleFilterStr.ToLower();
            bool needAdd = false;
            for (int i = 0; i < guiStyles.Count; i++)
            {
                if (string.IsNullOrEmpty(tempStr))
                {
                    needAdd = true;
                }
                else
                {
                    if (guiStyles[i].name.ToLower().Contains(tempStr))
                    {
                        needAdd = true;
                    }
                    else
                    {
                        needAdd = false;
                    }
                }

                if (needAdd)
                {
                    showGuiStyleList.Add(guiStyles[i]);
                }
            }
        }
    }
    /// <summary>
    /// 获取所有内置的风格
    /// </summary>
    private void GetAllEditorStyles()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值