【狂雲歌之unity_vr】unity裡獲取text中文字寬度並截斷省略

cloudysong發表於2017-01-22

【狂雲歌之unity_vr】unity裡獲取text中文字寬度並截斷省略

unityvr

前言

 在unity的ugui中Text控制元件,有時我們會有各種各樣的需求,比如類似html中css的text-overflow屬性,希望一段文字如果不夠長就全顯示,如果特別長就截斷並且後面加上例如...這種字尾。

 好吧這樣的需求在ugui裡貌似沒有現成的方法,如果有的話麻煩指點一下~

實現

 大概的思路就是 - 首先要能判斷什麼時候overflow - 並且支援加上字尾

 那麼text控制元件本來是支援overflow然後直接截斷的,但是比較暴力,直接砍斷,不能加字尾,並不滿足我們的需求。

 然後如果簡單的通過字元個數截斷,那根本不行,如果根據中英文字元來根據長度截斷,這個我試過,然而字型並不一定是一箇中文相當於倆英文字元,於是乎如果有一大排lllll或者iii什麼的,悲劇無以言表。

 所以我們需要知道一段文字所對應的渲染之後的長度。如果從text的preferwidth或者通過新增content size filter元件應該也能完成類似任務,不過我傾向於直接算好長度去填充。

 這個功能核心程式碼為 ``` 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;

} ```

 其中text為Text文字控制元件,RequestCharactersInTexture主要相當於指定需要渲染哪些字元(然後根據CharacterInfo.characterInfo是可以拿到本次生成的去重後的字符集)。接下來通過myFont.GetCharacterInfo(c, out characterInfo, text.fontSize);分別去獲得每個字元的資訊,然後characterInfo.advance就拿到了每個字元的渲染長度。

 拿到每個字元長度之後那就簡單多了,計算一下需要截斷的字元總長度,如果大於限制長度,就除去字尾長度後,擷取子字串,然後再接上字尾。這個事情就搞定了。

效果如下:

out

全部如下,這個例子是需要一個text和一個button,點選button,隨機生成文字在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 = { "是都", "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()
{
    //計算字尾的長度
    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);
    //截斷text的長度,如果總長度大於限制的最大長度,
    //那麼先根據最大長度減去字尾長度的值拿到字串,在拼接上字尾
    if (len > maxWidth)
    {
        return StripLength(input, maxWidth - suffixWidth) + suffix;
    }else
    {
        return input;
    }
}

//隨機生成個字串
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>
/// 根據maxWidth來截斷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>
/// 計算字串在指定text控制元件中的長度
/// </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;
}

} ```

後續

這個效果基本達到要求,如果仔細看的話,並不能保證每個擷取後的字串一定是對齊的,這個也跟字串有關,畢竟字串長度是離散的,貌似沒有辦法像word一樣在一行多一個文字的時候還可以擠一擠放下~

VR開發或者unity相關交流可以郵件madcloudsong@qq.com 轉載請註明原文連結 http://blog.csdn.net/madcloudsong/article/details/54670045

相關文章