原因

当字符串中带有半角空格,且半角空格后面的字符串内容超过文本剩余显示宽度时,Text组件会将后面的整段文字做换行。这个并不是bug,而是Text组件按照拉丁西语的分词习惯做line break,半角空格相当于分隔符,分隔空格前后的内容,并视之为单词。这种分词规则在西语中是正确的,但用在中文就水土不服了:整段的中文内容,粗暴地按半角空格分成了3部分,第一行空格后面的大段文字被判定为一个单词,剩余宽度无法显示,就被整个换到了第二行。

解决方案

解决原理很简单,如果碰到首字符是标点符号,那么就提前一个字符或者多个字符让他换行就可以了。
如果对中文排版要求比较高,就要考虑自己动手做Text的布局实现了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Text))]
public class TextFit : MonoBehaviour
{
/// <summary>
/// 用于匹配标点符号(正则表达式)
/// </summary>
private readonly string strRegex = @"\p{P}";

/// <summary>
/// 用于存储text组件中的内容
/// </summary>
private System.Text.StringBuilder MExplainText = null;

/// <summary>
/// 用于存储text生成器中的内容
/// </summary>
private IList<UILineInfo> MExpalinTextLine;

public IEnumerator MClearUpExplainMode(string _text)
{
_text = _text.Replace(" ", "");
_text = _text.Replace("\t", "");
_text = _text.Replace(" ", "");
if (_text[0] != '\u3000')
{
_text = "\u3000\u3000" + _text;
_text = _text.Replace("\n", "\n\u3000\u3000");
}

Text _component = transform.GetComponent<Text>();
_component.text = _text;
yield return new WaitForSeconds(0.001f);
MExpalinTextLine = _component.cachedTextGenerator.lines;
//需要改变的字符序号
int mChangeIndex = 0;
bool Is_H = false;

MExplainText = new System.Text.StringBuilder(_component.text);
for (int i = 1; i < MExpalinTextLine.Count; i++)
{
if (_component.text.Length > MExpalinTextLine[i].startCharIdx)
{

//首位是否有
bool _b = Regex.IsMatch(_component.text[MExpalinTextLine[i].startCharIdx ].ToString(), strRegex);
if (_b)
{
int DD = 1;
while (true)
{
bool _bb = Regex.IsMatch(_component.text[MExpalinTextLine[i].startCharIdx - DD].ToString(), strRegex);
if (!_bb)
{
Is_H = true;
mChangeIndex = MExpalinTextLine[i].startCharIdx - 1;
MExplainText.Insert(mChangeIndex - (DD - 1), "\n");
_component.text = MExplainText.ToString();
StartCoroutine(MClearUpExplainMode(MExplainText.ToString()));
break;
}
else
{
DD++;
}
}
if (Is_H)
break;
}
}
}
_component.text = MExplainText.ToString();
}
}

使用方法

1
2
var textFit = gameObject.GetComponent<TextFit>();
StartCoroutine(textFit.MClearUpExplainMode(info));