Get the text width in text and truncate the omitted operation in unity

Time:2022-5-7

preface

In the ugui of unity, we sometimes have various requirements for the text control, such as the text overflow attribute of CSS in HTML. We want to display a paragraph of text if it is not long enough, truncate it if it is especially long, and add a suffix such as… After it.

Well, there seems to be no ready-made method for such requirements in ugui. If so, please give me some advice~

realization

The general idea is

-First, you should be able to judge when to overflow

-And support adding suffixes

The text control originally supports overflow and then directly truncates, but it is violent and directly truncated without suffix, which does not meet our needs.

Then, if you simply truncate by the number of characters, it won’t work at all. If you truncate according to the length according to Chinese and English characters, I’ve tried this. However, the font is not necessarily a Chinese equivalent to two English characters. Therefore, if there is a large row of lllll or III, the tragedy is beyond words.

So we need to know the length of a text after rendering. Similar tasks can also be completed from the text’s preferwidth or by adding the content size filter component, but I prefer to calculate the length directly to fill.

The core code of this function is


Font myFont = text.font;  //chatText is my Text component
myFont.RequestCharactersInTexture(message, text.fontSize, text.fontStyle);
CharacterInfo characterInfo = new CharacterInfo();
char[] arr = message.ToCharArray();
foreach (char c in arr)
{
    myFont.GetCharacterInfo(c, out characterInfo, text.fontSize);
    totalLength += characterInfo.advance;
}

Where text is the text control, and requestcharactersintexture is mainly equivalent to specifying which characters need to be rendered (then according to characterinfo.characterinfo, you can get the de duplicated character set generated this time). Next, through myfont GetCharacterInfo(c, out characterInfo, text.fontSize); Get the information of each character separately, and then CharacterInfo Advance gets the rendering length of each character.

After getting the length of each character, it is much simpler. Calculate the total length of the characters to be truncated. If it is greater than the limit length, remove the suffix length, intercept the substring, and then connect the suffix. It’s done.

All are as follows. This example requires a text and a button. Click button to randomly generate text on text.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TextWidth : MonoBehaviour {
    public Text text;
    public Button button;
    const string suffix = "...";
    const int MAX_WIDTH = 200;
    int suffixWidth = 0;
    String [] seeds = {"yes", "60 °", "Q の", "[]", "d a", "as", "WW", "II", "Fs", "as", "WW", "II", "Fs"};
    // Use this for initialization
    void Start () {
        Init();
        button.onClick.AddListener(Rand);
    }
    void Init()
    {
        //Calculate the length of the suffix
        suffixWidth = CalculateLengthOfText(suffix);
        Debug.Log("suffixWidth : " + suffixWidth);
    }
    string StripLengthWithSuffix(string input, int maxWidth = MAX_WIDTH)
    {
        int len = CalculateLengthOfText(input);
        Debug.Log("input total length = " + len);
        //Truncate the length of text. If the total length is greater than the maximum length of the limit,
        //First, subtract the suffix length from the maximum length to get the string, and then splice the suffix
        if (len > maxWidth)
        {
            return StripLength(input, maxWidth - suffixWidth) + suffix;
        }else
        {
            return input;
        }
    }
    //Randomly generate a string
    void Rand()
    {
        int min = 12;
        int max = 16;
        int num = (int)(Random.value * (max - min) + min);
        Debug.Log("-------------------------\n num : " + num);
        string s = "";
        for (int j = 0; j < num; j++)
        {
            int len = seeds.Length;
            int index = (int)(Random.value * (len));
            s += seeds[index];
        }
        Debug.Log("s : " + s);
        text.text = StripLengthWithSuffix(s);
        Debug.Log("StripLength " + text.text);
    }
    /// <summary>
    ///Get the sub string according to the width input
    /// </summary>
    /// <param name="input"></param>
    /// <param name="maxWidth"></param>
    /// <returns></returns>
    string StripLength(string input, int maxWidth = MAX_WIDTH)
    {
        int totalLength = 0;
        Font myFont = text.font;  //chatText is my Text component
        myFont.RequestCharactersInTexture(input, text.fontSize, text.fontStyle);
        CharacterInfo characterInfo = new CharacterInfo();
        char[] arr = input.ToCharArray();
        int i = 0;
        foreach (char c in arr)
        {
            myFont.GetCharacterInfo(c, out characterInfo, text.fontSize);
            int newLength = totalLength + characterInfo.advance;
            if (newLength > maxWidth)
            {
                Debug.LogFormat("newLength {0},  totalLength {1}: ", newLength, totalLength);
                if (Mathf.Abs(newLength - maxWidth) > Mathf.Abs(maxWidth - totalLength)){
                    break;
                }else
                {
                    totalLength = newLength;
                    i++;
                    break;
                }
            }
            totalLength += characterInfo.advance;
            i++;
        }
        Debug.LogFormat("totalLength {0} : ", totalLength);
        return input.Substring(0, i);
    }
    /// <summary>
    ///Calculates the length of the string in the specified text control
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    int CalculateLengthOfText(string message)
    {
        int totalLength = 0;
        Font myFont = text.font;  //chatText is my Text component
        myFont.RequestCharactersInTexture(message, text.fontSize, text.fontStyle);
        CharacterInfo characterInfo = new CharacterInfo();
        char[] arr = message.ToCharArray();
        foreach (char c in arr)
        {
            myFont.GetCharacterInfo(c, out characterInfo, text.fontSize);
            totalLength += characterInfo.advance;
        }
        return totalLength;
    }
}

follow-up

This effect basically meets the requirements. If you look carefully, you can’t guarantee that each intercepted string must be aligned. This is also related to the string. After all, the length of the string is discrete. It seems that there is no way to squeeze it when there is more than one text in a line like word~

Supplement: unity text text hyperbox, with ‘…’ at the end ellipsis

//Hyperbox display
        public static void SetTextWithEllipsis(this Text textComponent, string value)
        {
            var generator = new TextGenerator();
            var rectTransform = textComponent.GetComponent<RectTransform>();
            var settings = textComponent.GetGenerationSettings(rectTransform.rect.size);
            generator.Populate(value, settings);
            var characterCountVisible = generator.characterCountVisible;
            var updatedText = value;
            if (value.Length > characterCountVisible)
            {
                updatedText = value.Substring(0, characterCountVisible - 3);
                updatedText += "…";
            }
            textComponent.text = updatedText;
        }

Call method: call once when assigning a value to text


text.SetTextWithEllipsis(titleDesc);

The effect is as follows:

The above is my personal experience. I hope I can give you a reference, and I hope you can support developpaer. If there are mistakes or not fully considered, please don’t hesitate to comment.

Recommended Today

Android uses COS and sin to draw compound curve animation

catalogue preface First analysis Second analysis summary preface During the development of new requirements in the first two weeks, an animation similar to this was designed: It’s not difficult to see. Even if I can’t understand it again, hey, there’s no design draft. As an Android Developer who seldom writes animation, when I see the […]