介绍

Unity 中有时会需要将不同界面下的字体统一为一个字体,或者需要整体更换字体,可以使用工具处理。

需求

将指定字体替换为另一个字体,因此需要同时指定源字体和目标字体。

需要同时替换 Prefab 与场景中的 UI 字体。

环境

  • Unity 2017.4.2f2

截图

FontChanger

代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;

public class FontChanger : EditorWindow
{
    [MenuItem("Tools/Font/Changer")]
    public static void Menu()
    {
        var window = GetWindow<FontChanger>();
        window.Show();
    }

    private void OnGUI()
    {
        EditorGUILayout.PrefixLabel("Source Font");
        _sourceFont = EditorGUILayout.ObjectField(_sourceFont, typeof(Font), false) as Font;
        EditorGUILayout.PrefixLabel("Target Font");
        _targetFont = EditorGUILayout.ObjectField(_targetFont, typeof(Font), false) as Font;

        GUILayout.BeginHorizontal();

        if (GUILayout.Button("Reset"))
        {
            ResetFont();
        }

        if (_sourceFont != null && _targetFont != null)
        {
            GUI.backgroundColor = Color.green;
        }
        else
        {
            GUI.backgroundColor = Color.red;
        }

        if (GUILayout.Button("Change") && _sourceFont != null && _targetFont != null)
        {
            ChangeAllPrefabs();
            ChangeAllScenes();
        }

        GUI.backgroundColor = Color.white;
        GUILayout.EndHorizontal();
    }

    private static void ResetFont()
    {
        _sourceFont = SystemFont;
        _targetFont = null;
    }

    private static void ChangeAllPrefabs()
    {
        var guids = AssetDatabase.FindAssets("t:Prefab");

        foreach (var guid in guids)
        {
            string path = AssetDatabase.GUIDToAssetPath(guid);
            var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
            ChangePrefab(prefab);
        }

        AssetDatabase.SaveAssets();
    }

    public static void ChangePrefab(GameObject prefab, bool ignoreSourceFont = false)
    {
        bool hasChanged = ChangeFont(prefab, ignoreSourceFont);
        if (hasChanged)
        {
            EditorUtility.SetDirty(prefab);
        }
    }

    private static void ChangeAllScenes()
    {
        var guids = AssetDatabase.FindAssets("t:Scene");

        foreach (var guid in guids)
        {
            var scenePath = AssetDatabase.GUIDToAssetPath(guid);
            ChangeScene(scenePath);
        }
    }

    public static void ChangeScene(string scenePath, bool ignoreSourceFont = false)
    {
        Scene scene = EditorSceneManager.OpenScene(scenePath);
        bool hasChanged = false;
        foreach (var go in scene.GetRootGameObjects())
        {
            hasChanged |= ChangeFont(go, ignoreSourceFont);
        }

        if (hasChanged)
        {
            EditorSceneManager.MarkSceneDirty(scene);
        }

        EditorSceneManager.SaveOpenScenes();
    }

    private static bool ChangeFont(GameObject prefab, bool ignoreSourceFont = false)
    {
        Text[] texts = prefab.GetComponentsInChildren<Text>(true);

        bool hasChanged = false;
        foreach (var text in texts)
        {
            if (ignoreSourceFont || text.font == _sourceFont)
            {
                text.font = _targetFont;

                hasChanged = true;
            }
        }

        return hasChanged;
    }

    public static Font SystemFont
    {
        get { return Resources.GetBuiltinResource<Font>("Arial.ttf"); }
    }

    public static Font _sourceFont;
    public static Font _targetFont;
}