具体流程:
通过AssetDatabase.FindAssets找到工程中包含的所有字体:
private List FindAllFonts()
{
List list = new List();
// 获取所有字体文件
string[] fontGUIDs = AssetDatabase.FindAssets("t:Font");
foreach (string fontGUID in fontGUIDs)
{
string fontPath = AssetDatabase.GUIDToAssetPath(fontGUID);
Font font = AssetDatabase.LoadAssetAtPath(fontPath);
list.Add(font.name);
}
list.Add("Arial");//默认字体添加进去
return list;
}
通过AssetDatabase.FindAssets找到工程中的所有预制体
private List GetAllPrefabByAssetDatabase(params string[] path)
{
List _prefabList = new List();
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(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(true);
foreach (var text in texts)
{
_prefabList.Add(text.gameObject);
}
}
#endif
return _prefabList;
}
过滤没有含Text组件的对象
private List FilterNoTextPrefabs()
{
List templist = new List();
Dic_Font_Prefabs.Clear();
foreach (var prefab in prefabs)
{
Text[] texts = prefab.GetComponentsInChildren(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());//根据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;
///
/// 查找替换工程场景中Text的Font
///
public class ChangePrefabFont : EditorWindow
{
[MenuItem("Tools/替换字体/Text")]//入口
static void GetWindow()//静态函数
{
//创建窗口
ChangePrefabFont window = EditorWindow.GetWindow("Text字体替换窗口");//生成一个unity窗口弹窗
window.Show();//展示OnGUI中的界面显示
}
#region 属性
///
/// 工程中包含的字体的名字
///
List fontsOnAssets = new List();
///
/// 对应字体是否需要替换
///
List textPaidFontRelpace = new List();
///
/// 代替要替换的字体的字体
///
List textReplaceFonts = new List();
///
/// 预制体集合
///
List prefabs = new List();
///
/// 根据字体类型分类的预制体对象
///
Dictionary> Dic_Font_Prefabs = new Dictionary>();
#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 ReplaceGo = new List();
Dictionary Dic_Font_ReplaceFont = new Dictionary();
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 逻辑方法
///
/// 字体相关初始化
///
private void InitFont()
{
textPaidFontRelpace.Clear();
textReplaceFonts.Clear();
fontsOnAssets = FindAllFonts();
foreach (var item in fontsOnAssets)
{
textPaidFontRelpace.Add(false);
textReplaceFonts.Add(null);
}
}
///
/// 预制体相关初始化
///
private void InitPrefabs()
{
prefabs = GetAllPrefabByAssetDatabase();
prefabs = FilterNoTextPrefabs();
prefabs.Clear();
foreach (var item in Dic_Font_Prefabs)
{
prefabs.AddRange(item.Value);
}
}
///
/// 初始化链表操作对象
///
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 查找和过滤
///
/// 找到工程和场景中的含有Text组件的对象
///
///
///
private List GetAllPrefabByAssetDatabase(params string[] path)
{
List _prefabList = new List();
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(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(true);
foreach (var text in texts)
{
_prefabList.Add(text.gameObject);
}
}
#endif
return _prefabList;
}
///
/// 过滤没有包含Text的预制体
/// 过滤没有包含付费字体的预制体
/// 根据Text类型分类
///
///
///
private List FilterNoTextPrefabs()
{
List templist = new List();
Dic_Font_Prefabs.Clear();
foreach (var prefab in prefabs)
{
Text[] texts = prefab.GetComponentsInChildren(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());//根据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;
}
///
/// 找到工程中的所有字体文件
///
/// 返回字体名称列表
private List FindAllFonts()
{
List list = new List();
// 获取所有字体文件
string[] fontGUIDs = AssetDatabase.FindAssets("t:Font");
foreach (string fontGUID in fontGUIDs)
{
string fontPath = AssetDatabase.GUIDToAssetPath(fontGUID);
Font font = AssetDatabase.LoadAssetAtPath(fontPath);
list.Add(font.name);
}
list.Add("Arial");//默认字体添加进去
return list;
}
#endregion
#region 替换字体方法
///
/// 替换Text的字体
///
/// 要替换的Text集合
/// 要替换的字体的名字
/// 用来替换的字体
private void ReplaceFont(List gameObjects, string fontName, Font font)
{
foreach (var go in gameObjects)
{
Text[] texts = go.GetComponentsInChildren(true);
foreach (var text in texts)
{
if (text.font != null)
{
if (text.font.name == fontName)
{
text.font = font;
}
}
//else
//{
// text.font = Resources.GetBuiltinResource("Arial.ttf");
//}
}
}
}
///
/// 保存更改
///
///
private void SaveChangedToAsset(List gameObjects)
{
foreach (var gameObject in gameObjects)
{
EditorUtility.SetDirty(gameObject);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("提示", "替换完毕!", "确定");
}
#endregion
private List GetUseFontPrefabs(string font)
{
if (Dic_Font_Prefabs.ContainsKey(font))
return Dic_Font_Prefabs[font];
else
return null;
}
private int GetGetUseFontPrefabCount(string font)
{
List temp = GetUseFontPrefabs(font);
return temp == null ? 0 : temp.Count;
}
#endregion
}