[Unity] カスタムTextコンポーネントで省略表示をする

#はじめに
Unityでテキストが表示範囲内に収まらない場合に文字をトリミングして省略文字を表示するカスタムTextコンポーネントを作成しました。
<img width="561" alt="Image01_20190526.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424358/af911fbf-55b3-14fb-00e3-00e2dea72b90.png">

#環境
Unity 2018.2.18.f1

#ソースコード
```
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class TrimmingText : Text
{
    // 省略時に表示する文字列
    private string ellipse = "...";

    // テキスト
    private string _text;

    public new string text
    {
        get { return _text; }
        set
        {
            _text = value;
            UpdateText(_text);
        }
    }

    // Text の RectTransform
    private RectTransform _rectTransform;

    public RectTransform _RectTransform
    {
        get
        {
            if (_rectTransform == null)
                _rectTransform = GetComponent<RectTransform>();
            return _rectTransform;
        }
    }

    // RectTransformのサイズ変更時に呼び出される
    protected override void OnRectTransformDimensionsChange()
    {
        base.OnRectTransformDimensionsChange();
        UpdateText(_text);
    }

    // ロードされた時やインスペクターの値が変更されたときに呼び出される
    protected override void OnValidate()
    {
        base.OnValidate();
        _text = m_Text;
        UpdateText(_text);
    }

    // テキストの更新
    private void UpdateText(string str)
    {

        // RichTextはタグの解析をしていないため未対応（タグがトリムされてしまう）
        if (supportRichText)
        {
            throw new Exception("Richtext is not supported");
        }
        else
        {
            // 文字列がない場合は以降の処理をしない
            if (string.IsNullOrWhiteSpace(str))
            {
                return;
            }

            // 設定されたテキスト情報を元にジェネレータを作成する
            var generator = new TextGenerator();
            var settings = this.GetGenerationSettings(_RectTransform.rect.size);
            generator.Populate(str, settings);

            // 0行の場合は、以降の処理を行わない
            if (generator.lineCount <= 0)
            {
                return;
            }

            var updatedText = str;

            // horizontalOverflow = warp
            if (HorizontalWrapMode.Wrap.Equals(horizontalOverflow))
            {
                var height = generator.GetPreferredHeight(updatedText, settings) / settings.scaleFactor;

                // generatorで設定されたテキスト領域高が、RectTransform高を超える場合はトリムを行う
                if (_RectTransform.rect.size.y < height)
                {
                    updatedText += ellipse;
                    height = generator.GetPreferredHeight(updatedText, settings) / settings.scaleFactor;

                    // generatorで設定されたテキスト領域高が、RectTransform高を超えないようになるまで文字を削除する
                    while (_RectTransform.rect.size.y < height && ellipse.Length < updatedText.Length)
                    {
                        updatedText = updatedText.Remove(updatedText.Length - ellipse.Length - 1, 1);
                        height = generator.GetPreferredHeight(updatedText, settings) / settings.scaleFactor;
                    }
                }
            }

            // horizontalOverflow = overflow
            else
            {
                var width = generator.GetPreferredWidth(updatedText, settings) / settings.scaleFactor;

                // generatorで設定されたテキスト領域幅が、RectTransform幅を超える場合はトリムを行う
                if (_RectTransform.rect.size.x < width)
                {
                    updatedText += ellipse;
                    width = generator.GetPreferredWidth(updatedText, settings) / settings.scaleFactor;

                    // generatorで設定されたテキスト領域幅が、RectTransform幅を超えないようになるまで文字を削除する
                    while (_RectTransform.rect.size.x < width && ellipse.Length < updatedText.Length)
                    {
                        updatedText = updatedText.Remove(updatedText.Length - ellipse.Length - 1, 1);
                        width = generator.GetPreferredWidth(updatedText, settings) / settings.scaleFactor;
                    }
                }
            }
            m_Text = updatedText;
        }
    }
}

```
#使い方
Textコンポーネントの代わりに「TrimmingText」をアタッチしてください。
<img width="275" alt="Image02_20190526.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/424358/424741df-aa2a-27a4-400a-189a1b91d463.png">
#解説
 - 「TextGenerator」で生成された文字列の表示範囲がRectTransformの範囲を超える場合、文字列をトリミングして「...」を表示します。
 - 「HorizontalOverflow」の「Overflow」「Warp」の両方に対応させています。「Overflow」の場合は、文字列の幅を監視し、「Warp」の場合は高さを監視してトリミング位置を判定します。
 - RichTextなどの一部の機能が正常動作しないためご注意ください。また表示幅が非常に狭いなど特定の条件下では正しく動作しません。

#免責事項
- 本記事に掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。また本記事に記載されているリンクなどによって他のサイトに移動した場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。
- 本記事に記載されているソースコードの利用は自己責任でお願い致します。プログラムの利用で生じるすべての損害に関して、利用者がその一切の責任を負うものとし、当方は一切の責任を負いません。