LoginSignup
2
1

More than 1 year has passed since last update.

【Unity】TextMeshProのAutoSizeは重いと聞いたので、任意のタイミングでフォントサイズを調整できるコンポーネントを作った

Last updated at Posted at 2021-05-15

(2022/01/09) 改良版を作りました

概要

TMP の AutoSize は処理負荷が重いと聞いたので、任意のタイミングでフォントサイズを調整できるコンポーネント「FontSizeFitter」を作りました。
gif.gif

コード

Text
TextFontSizeGoodFitter.cs
using UnityEngine;
using UnityEngine.UI;

public class FontSizeFitter : MonoBehaviour
{
    const float CONTENT_RATE = 0.95f;

    [SerializeField] bool updateOnAwake = true, everyUpdate = true;
    [SerializeField] Text text;
    int startFontSize;
    Rect rect;

    private void Start()
    {
        text.horizontalOverflow = HorizontalWrapMode.Overflow;
        startFontSize = text.fontSize;
        rect = text.rectTransform.rect;

        if (updateOnAwake) UpdateFontSize(rect, text, startFontSize);
    }

    private void Update()
    {
        if (everyUpdate) UpdateFontSize(rect, text, startFontSize);
    }

    private void OnValidate()
    {
        if (text == null) TryGetComponent<Text>(out text);
    }

    /// <summary>
    /// フォントサイズを更新
    /// </summary>
    /// <param name="text">Textを表示するRect。nullでも可</param>
    /// <param name="text">Text</param>
    /// <param name="baseSize">文字が表示される最大のフォントサイズより少し小さい値を指定してください。精度に影響します</param>
    public static void UpdateFontSize(Rect rect, Text text, int baseSize = 300)
    {
        text.fontSize = baseSize;
        float rateX = text.preferredWidth / rect.width;
        float rateY = text.preferredHeight / rect.height;

        if (rateX > rateY)
        {
            text.fontSize = (int)(baseSize / rateX * CONTENT_RATE);
        }
        else
        {
            text.fontSize = (int)(baseSize / rateY * CONTENT_RATE);
        }
    }
    public static void UpdateFontSize(Text text, int baseSize = 300) => UpdateFontSize(text.rectTransform.rect, text, baseSize);
}

TextMeshPro
TMP_FontSizeFitter.cs
using UnityEngine;
using TMPro;

public class TMP_FontSizeFitter : MonoBehaviour
{
    const float CONTENT_RATE = 0.95f;

    [SerializeField] bool updateOnAwake = true, everyUpdate = true;
    [SerializeField] TextMeshPro text;
    float startFontSize;
    Rect rect;

    private void Start()
    {
        text.overflowMode = TextOverflowModes.Overflow;
        startFontSize = text.fontSize;
        rect = text.rectTransform.rect;

        if (updateOnAwake) UpdateFontSize(rect, text, startFontSize);
    }

    private void Update()
    {
        if (everyUpdate) UpdateFontSize(rect, text, startFontSize);
    }

    private void OnValidate()
    {
        if (text == null) TryGetComponent<TextMeshPro>(out text);
    }

    /// <summary>
    /// フォントサイズを更新
    /// </summary>
    /// <param name="rect">Textを表示するRect。nullでも可</param>
    /// <param name="text">Text</param>
    /// <param name="baseSize">文字が表示される最大のフォントサイズより少し小さい値を指定してください。精度に影響します</param>
    public static void UpdateFontSize(Rect rect, TextMeshPro text, float baseSize = 300f)
    {
        text.fontSize = baseSize;
        float rateX = text.preferredWidth / rect.width;
        float rateY = text.preferredHeight / rect.height;

        if (rateX > rateY)
        {
            text.fontSize = baseSize / rateX * CONTENT_RATE;
        }
        else
        {
            text.fontSize = baseSize / rateY * CONTENT_RATE;
        }
    }
    public static void UpdateFontSize(TextMeshPro text, int baseSize = 300) => UpdateFontSize(text.rectTransform.rect, text, baseSize);
}

TextMeshPro UGUI
TMP_FontSizeFitter.cs
using UnityEngine;
using TMPro;

public class TMP_UGUI_FontSizeFitter : MonoBehaviour
{
    const float CONTENT_RATE = 0.95f;

    [SerializeField] bool updateOnAwake = true, everyUpdate = true;
    [SerializeField] TextMeshProUGUI text;
    float startFontSize;
    Rect rect;

    private void Start()
    {
        text.overflowMode = TextOverflowModes.Overflow;
        startFontSize = text.fontSize;
        rect = text.rectTransform.rect;

        if (updateOnAwake) UpdateFontSize(rect, text, startFontSize);
    }

    private void Update()
    {
        if (everyUpdate) UpdateFontSize(rect, text, startFontSize);
    }

    private void OnValidate()
    {
        if (text == null) TryGetComponent<TextMeshProUGUI>(out text);
    }

    /// <summary>
    /// フォントサイズを更新
    /// </summary>
    /// <param name="rect">Textを表示するRect。nullでも可</param>
    /// <param name="text">Text</param>
    /// <param name="baseSize">文字が表示される最大のフォントサイズより少し小さい値を指定してください。精度に影響します</param>
    public static void UpdateFontSize(Rect rect, TextMeshProUGUI text, float baseSize = 300f)
    {
        text.fontSize = baseSize;
        float rateX = text.preferredWidth / rect.width;
        float rateY = text.preferredHeight / rect.height;

        if (rateX > rateY)
        {
            text.fontSize = baseSize / rateX * CONTENT_RATE;
        }
        else
        {
            text.fontSize = baseSize / rateY * CONTENT_RATE;
        }
    }
    public static void UpdateFontSize(TextMeshProUGUI text, int baseSize = 300) => UpdateFontSize(text.rectTransform.rect, text, baseSize);
}

使い方

適当な GameObject に追加して、Text コンポーネントを参照してください(追加した時点で同じ GameObject 内に Text コンポーネントがあれば自動で参照します)。
フォントサイズは枠の中に「M」の1文字が丁度収まるくらいにするといい感じになります。面倒なら300(最大)にしてください。

備考

頻繁にフォントサイズを変更する文字には、きゃぶんずさんの AgileBestFit がおすすめです。
Text の HorizontalWrapMode はスクリプトによって Overflow に変更されます。不都合があれば Start() から消してください。
フォントサイズが少し大きくて文字が表示されない際は、CONTENT_RATE を小さくすると解決します。
TextMeshPro版は動作未確認なので、不具合があればコメントを下さい。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1