TextMeshProのAutoSizeは実行時に使うとめっちゃ重いのでAgileBestFitを使いましょう

ということで、ランタイムでも使える早いBestFitを作りました。
ただ描画後のサイズを取得してスケールを変えているだけです。
スケールを変更するので、初期スケールはVector3.oneになっていることを期待しています。
また、スケールを変更しているだけなのでAlignmentとRectTransformのPivotの設定によってはみ出たときの表示位置が変わります。
よしなに調整してください。
(AlignmentがLeftのときはPivot.x = 0.0, CenterのときはPivot.x = 0.5 RightのときはPivot.x == 1.0が想定する挙動だと思います。)

追記 : スケールをいじるということで、RectTransformをStretchにしてると正常に動作しないことが判明しました。使いにくいですね。

ランタイムでしか動きません。
Edit時に動かしたいなら標準のAutoSizeの方が優秀だからです。

/*
AgileBestFit

MIT License

Copyright (c) 2021 kyubuns

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

using System.Diagnostics;
using TMPro;
using UnityEngine;

namespace Sandbox
{
    [RequireComponent(typeof(TMP_Text))]
    public class AgileBestFit : MonoBehaviour
    {
        [SerializeField]
        [TextArea(5, 10)]
        public string editText;

        public float scaleMax = 1.0f;
        public float scaleMin = 0.0f;

        private TMP_Text _tmpTextCache;
        public TMP_Text TmpText
        {
            get
            {
                if (_tmpTextCache == null) _tmpTextCache = GetComponent<TMP_Text>();
                return _tmpTextCache;
            }
        }

        public string Text
        {
            get => TmpText.text;
            set
            {
                editText = value;
                TmpText.text = value;
                UpdateScale();
            }
        }

        [Conditional("UNITY_EDITOR")]
        public void Awake()
        {
            editText = Text;
        }

        [Conditional("UNITY_EDITOR")]
        public void Update()
        {
            if (editText == Text) return;
            Text = editText;
        }

        private void UpdateScale()
        {
            var preferredWidth = TmpText.preferredWidth;
            var s = Mathf.Clamp(TmpText.rectTransform.sizeDelta.x / preferredWidth, scaleMin, scaleMax);
            TmpText.rectTransform.localScale = new Vector3(s, s, s);
        }
    }
}

パフォーマンス測定

テキストを100回設定したとき

  • AutoSizing無し: 17.15ms
  • AutoSizing: 73.68ms
  • AgileBestFit: 24.52ms

以下、パフォーマンス測定用のコード。

var sampleData = new List<string>();
for (var i = 0; i < 100; ++i)
{
    sampleData.Add(new string(Enumerable.Range(0, i).Select(x => 'a').ToArray()));
}

{
    using (new Stopwatch("AutoSizing無し"))
    {
        foreach (var text in sampleData)
        {
            normal.text = text;
            normal.ForceMeshUpdate(true, true);
        }
    }
}

{
    using (new Stopwatch("AutoSizing"))
    {
        foreach (var text in sampleData)
        {
            autosize.text = text;
            autosize.ForceMeshUpdate(true, true);
        }
    }
}

{
    var tmp = agile.GetComponent<TextMeshPro>();
    using (new Stopwatch("AgileBestFit"))
    {
        foreach (var text in sampleData)
        {
            agile.Text = text;
            tmp.ForceMeshUpdate(true, true);
        }
    }
}