unity裡獲取text中文字寬度並截斷省略的操作
前言
在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就拿到瞭每個字符的渲染長度。
拿到每個字符長度之後那就簡單多瞭,計算一下需要截斷的字符總長度,如果大於限制長度,就除去後綴長度後,截取子字符串,然後再接上後綴。這個事情就搞定瞭。
全部如下,這個例子是需要一個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一樣在一行多一個文字的時候還可以擠一擠放下~
補充:Unity Text文字超框,末尾顯示‘…’省略號
// 超框顯示... 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; }
調用方式:在給Text賦值的時候調用一次即可
text.SetTextWithEllipsis(titleDesc);
效果如下:
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- None Found