[UIToolKit] 要素に合わせて文字サイズを動的に変更したい！

## 概要
UIToolKitで文字のサイズをUIElement内に収まるよう調整する方法について紹介します。

## バージョン
Unity 6 (6000.0.31f1)

## TextにあるFontSizeの%が機能しない
UXML上のfont-sizeにはpxと%の2種類からサイズを定義することができます。
pxを選択した場合、UIElementのサイズや画面サイズに問わず、常に同じピクセル数で文字が描画されます。
そのため、UIElementのサイズや画面サイズが変化すると、場合によっては文字が見えずらくなってしまいます。

#### 16:9 Aspectでフォントサイズ20の文字を画面いっぱいに表示した時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/a7090457-5f1f-4263-b716-f9cd65ccf5a3.png)

#### QHD (2560×1440)で同じように表示した時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/e3b6c8f7-7567-45f6-8a06-01c0d0e7a601.png)

そのため、FontSizeをpxではなく、%を使用することが望ましいのですが、現状%に変更しても何も変化しません。
どうやらこの問題は4年以上も前からバグとして機能していないもので、多くの人が解決してほしいとコメントを残しています。

https://discussions.unity.com/t/button-text-size-in-doesnt-work/824083/91

そのため、別の方法でfont-sizeを変更します。

## 解決法1 PanelSettingsを変更する
作成したUIを画面上に表示する際、UIDocumentというものを使用しますが、そこで設定するPanel SettingsのScale Modeをデフォルトの[Constant Pixel Size]から[Scale With Screen Size]に変更します。
そうすることで、画面サイズが変わった際に、[Scale Mode Parameters]にある解像度を基準にしてUI全体のサイズが調整されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/801de3f5-9312-49b2-a38d-31df709f7870.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/2126c4eb-7f52-434f-bf2f-f7be55d45aa7.png)

## 解決法2 フォントサイズを動的に変更するカスタムLabelを作成する
Labelを継承したCustomLabelを作成し、コード上で文字サイズを変更します。
作成したカスタムラベルでは、その要素に何文字表示させたいかを設定しておくことで、CustomLabelの情報が更新された際、要素の幅から一文字当たりの文字サイズを計算し、FontSizeに代入しています。
また、useRatioにチェックを入れることで、計算方法が要素の幅いっぱいからの割合に変化します。ratioの値を変更することで、要素の幅から文字サイズをどれだけ大きくするかを変更することができます。
しかし、Fontや太字などのStyle、全角半角等で文字サイズは異なるため、UIBuilder等で実際のサイズをみて調整してください。

#### (16:9 Aspectでフォントサイズ40の文字を画面いっぱいに表示した時)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/d8b5724c-6d86-4bf6-9c47-5e4343434ac3.png)

#### (QHD (2560×1440)で同じように表示した時)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4021403/fa27449f-6c66-47fc-b442-79880620a767.png)



### ソースコード(LabelAutoFit.cs)
```c#
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UIElements;

/// <summary>
/// 要素サイズに合わせて文字サイズを調整するカスタムUIElement
/// </summary>
/// <author>montake369</author>
/// <date>2025/03/03</date>
[UxmlElement]
partial class LabelAutoFit : Label
{
    [UxmlAttribute]
    [Tooltip("要素サイズからの割合で文字サイズを決定する")]
    bool useRatio { get; set; } = false;

    [UxmlAttribute]
    [Tooltip("1行あたりの最大文字数")]
    int charNum { get; set; } = 10;

    [UxmlAttribute]
    [Tooltip("割合")]
    float ratio { get; set; } = 1;

    public LabelAutoFit()
    {
        RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
    }

    private void OnAttachToPanel(AttachToPanelEvent e)
    {
        UnregisterCallback<AttachToPanelEvent>(OnAttachToPanel);
        RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
    }

    private void OnGeometryChanged(GeometryChangedEvent e)
    {
        UpdateFontSize();
    }

    private void UpdateFontSize()
    {
        try
        {
            float width = resolvedStyle.width - (resolvedStyle.paddingLeft + resolvedStyle.paddingRight);
            float height = resolvedStyle.height - (resolvedStyle.paddingTop + resolvedStyle.paddingBottom);
            
            float fontSize;
            if (useRatio) fontSize = math.max(0, math.min(width / text.Length * ratio, height));
            else fontSize = width / charNum;
            style.fontSize = new StyleLength(new Length(fontSize, LengthUnit.Pixel));
        }
        finally
        {
            
        }
    }
}
```

## 終わりに
要素サイズ等では正しく%が使用できますが、Textに関してだけ%が使用できず、これのせいでレスポンシブなUIを作成することができていない現状です。それにこの問題は4年も経過しており、いまだ修正されていないため、早く修正されてほしいです。