一键替换工程文件和场景中的UI对象字体

具体流程:

  1. 找到工程中使用到的所有字体
  2. 找到工程和场景中包含Text的所有对象
  3. 展示要替换的字体名字让用户选择
  4. 通过用户选择的字体,展示响应的物体对象
  5. 一键替换

通过AssetDatabase.FindAssets找到工程中包含的所有字体:

 private List<string> FindAllFonts()
    {
        List<string> list = new List<string>();
        // 获取所有字体文件
        string[] fontGUIDs = AssetDatabase.FindAssets("t:Font");
        foreach (string fontGUID in fontGUIDs)
        {
            string fontPath = AssetDatabase.GUIDToAssetPath(fontGUID);
            Font font = AssetDatabase.LoadAssetAtPath<Font>(fontPath);
            list.Add(font.name);
        }
        list.Add("Arial");//默认字体添加进去
        return list;
    }

 通过AssetDatabase.FindAssets找到工程中的所有预制体

  private List<GameObject> GetAllPrefabByAssetDatabase(params string[] path)
    {
        List<GameObject> _prefabList = new List<GameObject>();
        string[] _guids = AssetDatabase.FindAssets("t:Prefab", path);
        string _prefabPath = "";
        GameObject _prefab;
        foreach (var _guid in _guids)
        {
            _prefabPath = AssetDatabase.GUIDToAssetPath(_guid);
            _prefab = AssetDatabase.LoadAssetAtPath(_prefabPath, typeof(GameObject)) as GameObject;
            _prefabList.Add(_prefab);
        }
#if UNITY_2020_1_OR_NEWER
        Text[] texts = GameObject.FindObjectsOfType<Text>(true);
        foreach (var text in texts)
        {
            _prefabList.Add(text.gameObject);
        }
#else
        Scene activeScene = EditorSceneManager.GetActiveScene();
        GameObject[] allObjectsInScene = activeScene.GetRootGameObjects();
        foreach (var obj in allObjectsInScene)
        {
            Text[] texts = obj.GetComponentsInChildren<Text>(true);
            foreach (var text in texts)
            {
                _prefabList.Add(text.gameObject);
            }
        }
#endif
        return _prefabList;
    }

过滤没有含Text组件的对象

 private List<GameObject> FilterNoTextPrefabs()
    {
        List<GameObject> templist = new List<GameObject>();
        Dic_Font_Prefabs.Clear();
        foreach (var prefab in prefabs)
        {
            Text[] texts = prefab.GetComponentsInChildren<Text>(true);
            if (texts.Length != 0)
            {
                foreach (var text in texts)
                {
                    if (text.font != null)
                    {
                        if (!Dic_Font_Prefabs.ContainsKey(text.font.name))
                        {
                            Dic_Font_Prefabs.Add(text.font.name, new List<GameObject>());//根据Font类型,添加一个Text集合到字典中
                        }
                        if (!Dic_Font_Prefabs[text.font.name].Contains(prefab))
                        {
                            Dic_Font_Prefabs[text.font.name].Add(prefab);
                        }
                        if (!templist.Contains(prefab))
                        {
                            templist.Add(prefab);//包含该Text的预制体添加到集合中
                        }
                    }
                }
            }
        }
        return templist;
    }

最后,用户选择完要替换的字体,选择开始替换即可。

TextMeshPro跟Text是一个道理,只需要把代码中响应的Text和Font改为TextMeshProGUI和FontAssets即可。

最后附上完整代码:

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine.UI;
using System.Linq;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
/// <summary>
/// 查找替换工程场景中Text的Font
/// </summary>
public class ChangePrefabFont : EditorWindow
{
    [MenuItem("Tools/替换字体/Text")]//入口
    static void GetWindow()//静态函数
    {
        //创建窗口
        ChangePrefabFont window = EditorWindow.GetWindow<ChangePrefabFont>("Text字体替换窗口");//生成一个unity窗口弹窗
        window.Show();//展示OnGUI中的界面显示
    }

    #region 属性
    /// <summary>
    /// 工程中包含的字体的名字
    /// </summary>
    List<string> fontsOnAssets = new List<string>();
    /// <summary>
    /// 对应字体是否需要替换
    /// </summary>
    List<bool> textPaidFontRelpace = new List<bool>();
    /// <summary>
    /// 代替要替换的字体的字体
    /// </summary>
    List<Font> textReplaceFonts = new List<Font>();
    /// <summary>
    /// 预制体集合
    /// </summary>
    List<GameObject> prefabs = new List<GameObject>();
    /// <summary>
    /// 根据字体类型分类的预制体对象
    /// </summary>
    Dictionary<string, List<GameObject>> Dic_Font_Prefabs = new Dictionary<string, List<GameObject>>();
    #endregion
    private void OnEnable()
    {
        InitFont();
    }
    private void OnGUI()
    {
        InitPrefabs();
        #region 显示替换选项
        EditorGUILayout.LabelField("下面是工程中包含的字体,和工程中&场景中的对象使用的字体情况。请选择要替换的字体:");
        for (int i = 0; i < fontsOnAssets.Count; i++)
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField($"更换[{fontsOnAssets[i]}]字体");
            textPaidFontRelpace[i] = EditorGUILayout.Toggle(textPaidFontRelpace[i], GUILayout.Width(position.width));//是否要替换当前字体的复选框
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField($"    预制体数量:{GetGetUseFontPrefabCount(fontsOnAssets[i])}");
            if (!textPaidFontRelpace[i])
            {
                if (Dic_Font_Prefabs.ContainsKey(fontsOnAssets[i]))
                {
                    foreach (var item in Dic_Font_Prefabs[fontsOnAssets[i]])
                    {
                        if (prefabs.Contains(item))
                        {
                            prefabs.Remove(item);
                        }
                    }
                }
            }
            else
            {
                EditorGUILayout.LabelField($"代替【{fontsOnAssets[i]}】的字体:");
                textReplaceFonts[i] = (Font)EditorGUILayout.ObjectField(textReplaceFonts[i], typeof(Font), true);//代替的字体复选框

                if (Dic_Font_Prefabs.ContainsKey(fontsOnAssets[i]))
                {
                    foreach (var item in Dic_Font_Prefabs[fontsOnAssets[i]])
                    {
                        if (!prefabs.Contains(item))
                        {
                            prefabs.Add(item);
                        }
                    }
                }
            }
            EditorGUILayout.EndHorizontal();
        }
        EditorGUILayout.Space();
        #endregion
        #region 开始替换操作
        if (GUILayout.Button("开始替换"))
        {
            if (textReplaceFonts == null || textReplaceFonts.Count == 0)
            {
                EditorUtility.DisplayDialog("提示", "没有字体!", "确定");
                return;
            }
            if (prefabs == null || prefabs.Count == 0)
            {
                EditorUtility.DisplayDialog("提示", "没有需要替换的对象!", "确定");
                return;
            }
            List<GameObject> ReplaceGo = new List<GameObject>();
            Dictionary<string, Font> Dic_Font_ReplaceFont = new Dictionary<string, Font>();
            for (int i = 0; i < textPaidFontRelpace.Count; i++)
            {
                if (textPaidFontRelpace[i] == true)
                {
                    if (textReplaceFonts[i] != null)
                    {
                        if (Dic_Font_Prefabs.ContainsKey(fontsOnAssets[i]))
                        {
                            ReplaceGo.AddRange(Dic_Font_Prefabs[fontsOnAssets[i]]);
                            Dic_Font_ReplaceFont.Add(fontsOnAssets[i], textReplaceFonts[i]);
                        }
                        else
                        {
                            EditorUtility.DisplayDialog("提示", $"使用了【{fontsOnAssets[i]}】字体的预制体数量为0!", "确定");
                        }
                    }
                    else
                    {
                        EditorUtility.DisplayDialog("提示", $"【{fontsOnAssets[i]}】的替代字体为空!", "确定");
                    }
                }
            }
            if (ReplaceGo.Count == 0)
            {
                EditorUtility.DisplayDialog("提示", "没有需要替换的对象!", "确定");
            }
            else
            {
                string hintInfo = "";
                foreach (var font in Dic_Font_ReplaceFont)
                {
                    hintInfo += $"{font.Key} >> {font.Value.name}\n";
                }
                if (EditorUtility.DisplayDialog("确认进行下面的替换?", hintInfo, "确定", "取消"))
                {
                    foreach (var font in Dic_Font_ReplaceFont)
                    {
                        ReplaceFont(Dic_Font_Prefabs[font.Key], font.Key, font.Value);
                    }
                    SaveChangedToAsset(prefabs);
                }
            }
        }
        #endregion
        #region 预制体列表
        InitReorderableList();
        if (reorderableList != null && reorderableList.count != 0)
        {
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
            reorderableList.DoLayoutList();
            EditorGUILayout.EndScrollView();
        }
        else
        {
            EditorGUILayout.LabelField("提示:没有需要替换字体的预制体");
        }
        #endregion
    }
    #region 列表和滚动窗口
    ReorderableList reorderableList;//列表显示
    Vector2 scrollPos;//滚动窗口需要
    private void DrawHeader(Rect rect)
    {
        EditorGUI.LabelField(rect, "对象列表数量:" + prefabs.Count);
    }
    private void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
    {
        rect.height -= 4;
        rect.y += 2;
        prefabs[index] = (GameObject)EditorGUI.ObjectField(rect, "包含Text的对象", prefabs[index], typeof(GameObject), true);
    }
    private void AddItem(ReorderableList list)
    {
        prefabs.Add(null);
    }
    #endregion
    #region 逻辑方法
    /// <summary>
    /// 字体相关初始化
    /// </summary>
    private void InitFont()
    {
        textPaidFontRelpace.Clear();
        textReplaceFonts.Clear();
        fontsOnAssets = FindAllFonts();
        foreach (var item in fontsOnAssets)
        {
            textPaidFontRelpace.Add(false);
            textReplaceFonts.Add(null);
        }
    }
    /// <summary>
    /// 预制体相关初始化
    /// </summary>
    private void InitPrefabs()
    {
        prefabs = GetAllPrefabByAssetDatabase();
        prefabs = FilterNoTextPrefabs();
        prefabs.Clear();
        foreach (var item in Dic_Font_Prefabs)
        {
            prefabs.AddRange(item.Value);
        }

    }
    /// <summary>
    /// 初始化链表操作对象
    /// </summary>
    private void InitReorderableList()
    {
        prefabs = prefabs.Distinct().ToList();
        reorderableList = new ReorderableList(prefabs, typeof(GameObject), true, true, true, true);
        reorderableList.drawHeaderCallback = DrawHeader;
        reorderableList.drawElementCallback = DrawElement;
        reorderableList.onAddCallback = AddItem;
    }

    #endregion
    #region 功能方法
    #region 查找和过滤
    /// <summary>
    /// 找到工程和场景中的含有Text组件的对象
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private List<GameObject> GetAllPrefabByAssetDatabase(params string[] path)
    {
        List<GameObject> _prefabList = new List<GameObject>();
        string[] _guids = AssetDatabase.FindAssets("t:Prefab", path);
        string _prefabPath = "";
        GameObject _prefab;
        foreach (var _guid in _guids)
        {
            _prefabPath = AssetDatabase.GUIDToAssetPath(_guid);
            _prefab = AssetDatabase.LoadAssetAtPath(_prefabPath, typeof(GameObject)) as GameObject;
            _prefabList.Add(_prefab);
        }
#if UNITY_2020_1_OR_NEWER
        Text[] texts = GameObject.FindObjectsOfType<Text>(true);
        foreach (var text in texts)
        {
            _prefabList.Add(text.gameObject);
        }
#else
        Scene activeScene = EditorSceneManager.GetActiveScene();
        GameObject[] allObjectsInScene = activeScene.GetRootGameObjects();
        foreach (var obj in allObjectsInScene)
        {
            Text[] texts = obj.GetComponentsInChildren<Text>(true);
            foreach (var text in texts)
            {
                _prefabList.Add(text.gameObject);
            }
        }
#endif
        return _prefabList;
    }
    /// <summary>
    /// 过滤没有包含Text的预制体
    /// 过滤没有包含付费字体的预制体
    /// 根据Text类型分类
    /// </summary>
    /// <param name="gameObjects"></param>
    /// <returns></returns>
    private List<GameObject> FilterNoTextPrefabs()
    {
        List<GameObject> templist = new List<GameObject>();
        Dic_Font_Prefabs.Clear();
        foreach (var prefab in prefabs)
        {
            Text[] texts = prefab.GetComponentsInChildren<Text>(true);
            if (texts.Length != 0)
            {
                foreach (var text in texts)
                {
                    if (text.font != null)
                    {
                        if (!Dic_Font_Prefabs.ContainsKey(text.font.name))
                        {
                            Dic_Font_Prefabs.Add(text.font.name, new List<GameObject>());//根据Font类型,添加一个Text集合到字典中
                        }
                        if (!Dic_Font_Prefabs[text.font.name].Contains(prefab))
                        {
                            Dic_Font_Prefabs[text.font.name].Add(prefab);
                        }
                        if (!templist.Contains(prefab))
                        {
                            templist.Add(prefab);//包含该Text的预制体添加到集合中
                        }
                    }
                }
            }
        }
        return templist;
    }
    /// <summary>
    /// 找到工程中的所有字体文件
    /// </summary>
    /// <returns>返回字体名称列表</returns>
    private List<string> FindAllFonts()
    {
        List<string> list = new List<string>();
        // 获取所有字体文件
        string[] fontGUIDs = AssetDatabase.FindAssets("t:Font");
        foreach (string fontGUID in fontGUIDs)
        {
            string fontPath = AssetDatabase.GUIDToAssetPath(fontGUID);
            Font font = AssetDatabase.LoadAssetAtPath<Font>(fontPath);
            list.Add(font.name);
        }
        list.Add("Arial");//默认字体添加进去
        return list;
    }
    #endregion
    #region 替换字体方法
    /// <summary>
    /// 替换Text的字体
    /// </summary>
    /// <param name="texts">要替换的Text集合</param>
    /// <param name="fontName">要替换的字体的名字</param>
    /// <param name="font">用来替换的字体</param>
    private void ReplaceFont(List<GameObject> gameObjects, string fontName, Font font)
    {
        foreach (var go in gameObjects)
        {
            Text[] texts = go.GetComponentsInChildren<Text>(true);
            foreach (var text in texts)
            {
                if (text.font != null)
                {
                    if (text.font.name == fontName)
                    {
                        text.font = font;
                    }
                }
                //else
                //{
                //    text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
                //}
            }
        }
    }
    /// <summary>
    /// 保存更改
    /// </summary>
    /// <param name="gameObjects"></param>
    private void SaveChangedToAsset(List<GameObject> gameObjects)
    {
        foreach (var gameObject in gameObjects)
        {
            EditorUtility.SetDirty(gameObject);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        EditorUtility.DisplayDialog("提示", "替换完毕!", "确定");
    }
    #endregion
    private List<GameObject> GetUseFontPrefabs(string font)
    {
        if (Dic_Font_Prefabs.ContainsKey(font))
            return Dic_Font_Prefabs[font];
        else
            return null;
    }
    private int GetGetUseFontPrefabCount(string font)
    {
        List<GameObject> temp = GetUseFontPrefabs(font);
        return temp == null ? 0 : temp.Count;
    }
    #endregion
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值