【Unity】TextMeshProのAutoSizeは重いと聞いたので、フォントサイズをまとめて調整できる便利メソッドを作った

# 概要
[TMP の AutoSize は処理負荷が重い](https://forum.unity.com/threads/tmp-autosize-performance-vs-uguis-bestfit.525979/)と聞いたので、TextMeshPro を任意のタイミングで AutoSize（を模した処理）をする拡張メソッドを作りました。
また画像のように、複数の TextMeshPro から一番文字列の長い要素を探して AutoSize を行い、そのフォントサイズを全ての TextMeshPro に適応する便利メソッドも作りました。AutoSize を1回に抑え、見た目の統一感も保てます。
TextMeshPro の拡張クラスや便利クラスに追加してご利用ください。

![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/23c66fd5-4b2a-9fb5-5f90-7a7aee505b79.png)
![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/7550792e-5054-a6d5-d397-f09f6f6a4781.png)

# コード

<details><summary>TMProExtension.cs</summary><div>

``` TMProExtension.cs
using UnityEngine;
using TMPro;

/// <summary>
/// TextMeshProの拡張クラス
/// </summary>
public static class TMProExtension
{
    /// <summary>
    /// TextがRectに収まるように、フォントサイズを調整する
    /// </summary>
    /// <param name="text">Text</param>
    /// <param name="scale">Rectに対しての大きさ</param>
    /// <param name="maxSize">最大フォントサイズ</param>
    public static float FitFontSize(this TMP_Text text,
        float scale = 0.9f,
        float maxSize = 1024f)
    {
        text.fontSize = 1f;

        float textWidth = text.preferredWidth;
        float textHeight = text.preferredHeight;
        Rect rect = text.rectTransform.rect;
        float rectWidth = rect.width;
        float rectHeight = rect.height;

        if (text.text.Length == 0
            || Mathf.Approximately(textHeight, 0f)
            || Mathf.Approximately(rectWidth, 0f)
            || Mathf.Approximately(rectHeight, 0f)) return 0f;

        float rateX = textWidth / rectWidth;
        float rateY = textHeight / rectHeight;

        if (rateX > rateY) text.fontSize = Mathf.Min(maxSize, scale / rateX);
        else text.fontSize = Mathf.Min(maxSize, scale / rateY);

        return text.fontSize;
    }
}
```

</div></details>

<details><summary>TMProUtility.cs</summary><div>

``` TMProUtility.cs
using System.Collections.Generic;
using TMPro;

/// <summary>
/// TextMeshProの便利クラス
/// </summary>
public static class TMProUtility
{
    /// <summary>
    /// 一番文字列の長いTextを探し、自身のRectに収まるフォントサイズを計算。それを全てのTextのフォントサイズに適応する
    /// </summary>
    /// <param name="text">Text</param>
    /// <param name="scale">Rectに対しての大きさ</param>
    /// <param name="maxSize">最大フォントサイズ</param>
    public static void FitsAllFontSize(
        this TMP_Text[] texts,
        float scale = 0.9f,
        float maxSize = 256f)
    {
        // 最長文字列の TMP_Text を探す
        TMP_Text t = null;
        int maxLength = 0;
        foreach (var item in texts)
        {
            if (item.text.Length > maxLength)
            {
                t = item;
                maxLength = item.text.Length;
            }
        }

        // フォントサイズを決定
        float size = t.FitFontSize(scale, maxSize);

        // 全てのTextに適応
        foreach (var text in texts)
        {
            text.fontSize = size;
        }
    }
}
```

</div></details>

# 使い方

AutoSize（を模した処理）は下記で実行できます。重い処理です。

``` C#
text.FitFontSize();
```

引数は2つ用意されています。

``` C#
text.FitFontSize(scale: 0.9f, maxSize: 256f);
```

FitsAllFontSize を使うと、複数の TextMeshPro から一番文字列の長い要素を探して AutoSize を行い、そのフォントサイズを全ての TextMeshPro に適応できます。たくさん改行する文字列は上下にはみ出す恐れがあります。

``` C#
TMProUtility.FitsAllFontSize(texts);
```

こちらにも FitFontSize と同様の引数が用意されています。

``` C#
TMProUtility.FitsAllFontSize(texts, scale: 0.9f, maxSize: 256f);
```

# 補足
以前作った[任意のタイミングでフォントサイズを調整できるコンポーネント](https://qiita.com/Yamara/items/b3109a5901affb80c5e1)は、AutoSize の使用頻度を抑えられていない失敗作だと気づいたため、改良したものを作りました。