Ugui text 排版的bug
最近策劃反映了個問題,遊戲裡的多行文字會出現提前換行的問題,如下圖所示:
文字錯誤地提前換行,導致第一行文字後面有大塊空白區域
通過觀察可以發現,當字串中帶有半形空格,且半形空格後面的字串內容超過文字剩餘顯示寬度時,Text元件會將後面的整段文字做換行。這個並不是bug,而是Text元件按照拉丁西語的分詞習慣做line break,半形空格相當於分隔符,分隔空格前後的內容,並視之為單詞。這種分詞規則在西語中是正確的,但用在中文就水土不服了:整段的中文內容,粗暴地按半形空格分成了3部分,第一行空格後面的大段文字被判定為一個單詞,剩餘寬度無法顯示,就被整個換到了第二行。
0x02 解決方案v1
稍作思考,嘗試使用中文全形空格替換半形空格,換行正常,也就是說,分詞規則只對半形空格做處理。然而中文全形空格比半形空格要寬,導致文字間隙過大,顯示效果很差。
0x03 解決方案v2
那有沒有長得跟半形空格一樣,而又不會被底層分詞的字元呢?google一下,找到了答案不換行空格(Non-breaking Space)。
我們平時所使用的空格(即鍵盤Sapce鍵輸出的空格),Unicode編碼為/u0020,是換行空格(Breaking Space),空格前後的內容是允許自動換行的;與之對應的不換行空格(Non-breaking space),Unicode編碼為/u00A0,顯示與換行空格一樣,主要用途用於禁止自動換行,在英文中主要用於避免類似(100 KM)
那這下問題就好解決了,我們只需在Text元件設定text時,將字串的換行空格統一更換成不換行空格,就能解決換行錯誤問題。新建一個NonBreakingSpaceTextComponent類,做文字替換處理:
/* ============================================================================== * 功能描述:將Text元件的space(0x0020)替換為No-break-space(0x00A0),避免中文使用半形空格導致的提前換行問題 * 創 建 者:shuchangliu * ==============================================================================*/ using UnityEngine.UI; using UnityEngine; [RequireComponent(typeof(Text))] public class NonBreakingSpaceTextComponent : MonoBehaviour { public static readonly string no_breaking_space = "\u00A0"; protected Text text; // Use this for initialization void Awake () { text = this.GetComponent<Text>(); text.RegisterDirtyVerticesCallback(OnTextChange); } public void OnTextChange() { if (text.text.Contains(" ")) { text.text = text.text.Replace(" ", no_breaking_space); } } }
將NoBreakingSpaceTextComponent掛在Text元件上,每當Text設定text文字,準備重新繪製Text網格時,NoBreakingSpaceTextComponent會檢查並替換text文字裡的換行空格。 效果如圖所示,Mission Complete!
0x04 後記
從這個小問題可以看出Text的分詞規則是針對西語而言的,對中文分詞支援並不好,比如中文的標點符號不應該出現在行首。如果遊戲對中文排版要求比較高,就要考慮自己動手做Text的佈局實現了。