Unity

[Unity] Textコンポーネントでテキストを切り捨てずに全文表示させる方法

More than 1 year has passed since last update.
  • TextComponentにてテキスト(の1部)が切り捨てられ、表示されなくなる場合がある

truncate.png

原因

overflow.png

意図しない発生

また、以下のような要因で意図せず発生して、テキストが描画されなくなる場合があるので対策しておくに越したことは無い

  • フォントを差し替えた場合
  • Script等で動的に長いテキストを表示した場合
    • 特にユーザが任意に入力できるケース等
  • 編集中の状態とは異なる解像度の場合
    • AndroidやiOS等の実機での実行
    • UnityEditor上でのMaximize
    • CanvasScalarの設定変更 ... etc

解決方法

(1) TextComponentにてOverflowの設定を変更する

  • VerticalOverflowoverflow にすることによって垂直方向の描画領域を超えてもテキストが切り捨てられない
  • このアプローチで解消した場合、意図しない要素の垂直方向へのはみ出しに注意

verticaloverflow.gif

(2) TextComponentにてBestFitを指定する

  • https://docs.unity3d.com/ja/current/Manual/script-Text.html
  • Unity がサイズプロパティーを無視して、単にコントロールの矩形にテキストを合わせるようにするか
  • BestFitにチェックを入れると MinSize / MaxSize の項目が出現する
    • テキストが描画領域を超えた場合、フォントサイズを段階的に小さくするプロパティ
    • MaxSize にはデフォルトでFontSizeで指定した値が格納される
    • MinSize に設定した値よりフォントサイズが小さくなることはない
  • このアプローチで解消した場合、最大文字数に注意
    • スクリプト等で意図しない長さの文字を格納した場合、極端に小さくなってしまう

bestfit.gif

追記

# Best Fit とパフォーマンス
基本的には、UI TextコンポーネントのBest Fit設定は一切使用しないでください。
Best Fitの計算には膨大な量のテストが必要なので、これによって他のTextコンポーネントが使用しているグリフが削除されてしまい
適正なフォントサイズが算出された後に少なくとももう1回、フォントアトラスのリビルドが余儀なくされます。
フォントアトラスの頻繁なリビルドは、ランタイムのパフォーマンスを急激に劣化させるだけでなく、
メモリの断片化も引き起こします。この問題は、Best Fitに設定されたテキストコンポーネントの量が多ければ多いほど悪化します。

(3) ContentSizeFitterをアタッチする

csf.gif

(4) 余談: 長い文章に対してellipsis(...)を適応するScript

  • はみ出し/フォントの縮小を考慮したくない場合、もうテキスト自体を短くするしかない...!!
    • その場合、単に切り捨てるのではなく、ellipsisを付けて省略されたことを認知したい
  • 以下、テキストを当てはめつつ、描画領域を超えていたらellipsis(...)を付けるメソッド例
    • 文字数 > 描画される文字数を満たすときに ellipsis(...)を適応する
    • 上記の条件により、確実に全ての文字が描画される(1)~(3)のアプローチとの併用は出来ない
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

public static class TextExtension
{
    // XXX operating in no overflow (Horizonal|Vertical)
    public static void SetTextWithEllipsis(this Text textComponent, string value)
    {
        // create generator with value and current Rect
        var generator     = new TextGenerator();
        var rectTransform = textComponent.GetComponent<RectTransform>();
        var settings      = textComponent.GetGenerationSettings(rectTransform.rect.size);
        generator.Populate(value, settings);

        // trncate visible value and add ellipsis
        var characterCountVisible = generator.characterCountVisible;
        var updatedText = value;
        if (value.Length > characterCountVisible)
        {
            updatedText = value.Substring(0, characterCountVisible - 3);
            updatedText += "...";
        }

        // update text
        textComponent.text = updatedText;
    }
}

以下呼び出し例

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class TextTest : MonoBehaviour
{
    public string value;

    void Update()
    {
        this.GetComponent<Text>().SetTextWithEllipsis(value);
    }
}

ellipsis.gif