uGUIの"BestFit"とかTextMeshProの"AutoSize"、便利だけど流石にパフォーマンス的にヤバすぎん?って思って調べたら
— きゅぶんず (@kyubuns) 2021年5月11日
公式も「サイズ調べるために使うためのものでサイズわかったら切ってね」って言ってた
> TMP AutoSize performance vs UGUI's BestFit? https://t.co/dDiUOIQeYc
ということで、ランタイムでも使える早い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); } } }