using System;
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using System.Text.RegularExpressions;
[XLua.WhiteList]
public sealed class LText : Text
{
//是否跳过检测行首标点
private bool SkipMoveSymbol = false;
private readonly string matchPunctuation = @"\p{P}";
private readonly string specialSymbol = "…"; //省略号特殊处理,不能被截断
//private readonly string exceptPunctuation = @"(\<|\>|\[|\])";
//private readonly string exceptPunctuation = @"(\<|\[|\{)";
private readonly string openingBrackets = @"(\<|\[|\{|\(|《)";
//private readonly string endingBrackets = @"(\>|\]|\})";
private Vector2 m_RectTransformSize;
private TextGenerationSettings m_GenerationSettings;
private StringBuilder m_TextStrBuilder;
private StringBuilder TextStrBuilder
{
get { return m_TextStrBuilder ?? (m_TextStrBuilder = new StringBuilder()); }
}
public override string text
{
get { return m_Text; }
set
{
if (string.IsNullOrEmpty(value))
{
if (string.IsNullOrEmpty(m_Text))
return;
m_Text = "";
SetVerticesDirty();
}
else
{
if (!Application.isPlaying)
{
return;
}
if (!inParsing)
{
m_Text = ParseTextStr(value);
SetVerticesDirty();
SetLayoutDirty();
}
}
}
}
protected override void OnRectTransformDimensionsChange()
{
// 更新行数或其他逻辑文本的尺寸发生了变化
//组件上挂载的有ContentSizeFilter的时候计算行数会有问题,因此再次调用一下
m_Text = ParseTextStr(m_Text);
SetVerticesDirty();
SetLayoutDirty();
}
public override void SetVerticesDirty()
{
base.SetVerticesDirty();
m_RectTransformSize = rectTransform.rect.size;
m_GenerationSettings = GetGenerationSettings(m_RectTransformSize);
}
private bool inParsing = false;
//解析文本,看是否需要换行
private string ParseTextStr(string textStr)
{
if (!SkipMoveSymbol)
{
m_RectTransformSize = rectTransform.rect.size;
m_GenerationSettings = GetGenerationSettings(m_RectTransformSize);
inParsing = true;
textStr = moveLineLast(textStr);
inParsing = false;
}
return textStr;
}
#region 同步检测行首标点,要点在于while循环内重复调用PopulateWithErrors,获取tempTextGenerator.lines;
//private static readonly TextGenerator sTempTextGenerator = new TextGenerator();
private bool CheckMove(ref string tempStr)
{
//sTempTextGenerator.PopulateWithErrors(m_OutputText, m_GenerationSettings,gameObject);
cachedTextGenerator.PopulateWithErrors(tempStr, m_GenerationSettings, gameObject);
int changeIndex = -1;
int lengthStr = tempStr.Length;
for (int i = 1; i < cachedTextGenerator.lines.Count; i++)
{
int startMatchIndex = cachedTextGenerator.lines[i].startCharIdx;
if (startMatchIndex >= lengthStr)
{
break;
}
int preLineStartCharIdx = cachedTextGenerator.lines[i - 1].startCharIdx;
int preLineEndMatchIndex = cachedTextGenerator.lines[i].startCharIdx - 1;
int curLineStartCharIdx = cachedTextGenerator.lines[i].startCharIdx;
int preLineCharCount = curLineStartCharIdx - preLineStartCharIdx;
if (preLineCharCount == 1)
{
//如果上一行只有一个字符,则跳过
continue;
}
if (preLineEndMatchIndex < 0 || preLineEndMatchIndex >= tempStr.Length)
{
continue;
}
bool endStrMark = MatchLineEndStr(tempStr[preLineEndMatchIndex].ToString());
if (endStrMark)
{
//上一行行尾是成对符号的开始字符
changeIndex = preLineEndMatchIndex;
break;
}
string matchStr = tempStr[startMatchIndex].ToString();
//判断该行行首是否是符号
bool isMark = MatchPunctuation(matchStr);
if (isMark)
{
string preMatchStr = tempStr[preLineEndMatchIndex].ToString();
bool isPreLineEndMark = MatchPunctuation(preMatchStr);
if (preMatchStr.Equals("\n"))
{
MDebug.LogError("换行符和标点连用,策划看下是不是不符合版署要求:" + tempStr);
continue;
//isPreLineEndMark = true;
}
bool isCurSpecial = matchStr.Equals(specialSymbol);
if (isCurSpecial)
{
if (isPreLineEndMark)
{
//上一行末尾是省略号的前一半,多拉一个字符下来
changeIndex = FindMatchIndex(tempStr, preLineEndMatchIndex - 1);
break;
}
//如果当前符号是省略号
//判断省略号是否被截断
bool isCompletion = false;
int nextIndex = curLineStartCharIdx + 1;
if (nextIndex < lengthStr)
{
string nextStr = tempStr[nextIndex].ToString();
if (nextStr.Equals(specialSymbol))
{
//省略号完整
isCompletion = true;
}
}
if (isCompletion)
{
if (isPreLineEndMark)
{
//上一行末尾是符号
continue;
}
}
}
else
{
//不是省略号,但上一行末尾是标点,应该是标点连用的错误
if (isPreLineEndMark)
{
//上一行末尾是省略号的前一半,多拉一个字符下来
changeIndex = FindMatchIndex(tempStr, preLineEndMatchIndex - 1);
break;
}
}
changeIndex = preLineEndMatchIndex;
//颜色富文本处理
int subStartIndex = preLineStartCharIdx;
int subLength = curLineStartCharIdx - preLineStartCharIdx;
string str = tempStr.Substring(subStartIndex, subLength);
MatchCollection richStrMatch =
Regex.Matches(str, ".(</color>|<color=#\\w{6}>|" + matchPunctuation + ")+$");
if (richStrMatch.Count > 0)
{
string richStr = richStrMatch[0].ToString();
int length = richStr.Length;
changeIndex = curLineStartCharIdx - length;
break;
}
if (changeIndex >= 0)
{
break;
}
}
}
if (changeIndex >= 0)
{
TextStrBuilder.Clear();
TextStrBuilder.Append(tempStr);
TextStrBuilder.Insert(changeIndex, '\n');
tempStr = TextStrBuilder.ToString();
return true;
}
return false;
}
//找到非标点的index
private int FindMatchIndex(string _tempStr, int _preIndex)
{
int whileCount = 0;
while (_preIndex > 0)
{
string preMatchStr = _tempStr[_preIndex].ToString();
bool result = MatchPunctuation(preMatchStr);
if (!result)
{
return _preIndex;
}
--_preIndex;
++whileCount;
if (whileCount >= 1)
{
MDebug.LogError(_tempStr + "多个标点连用!!!");
return -1;
}
}
return -1;
}
//判断是否是符号
private bool MatchPunctuation(string matchStr)
{
bool isMark = Regex.IsMatch(matchStr, matchPunctuation);
bool isOpenBracket = Regex.IsMatch(matchStr, openingBrackets);
if (isMark && !isOpenBracket)
{
//如果是富文本用到的,则忽略
return true;
}
return false;
}
//判断行尾是否是成对字符的开始字符
private bool MatchLineStartStr(string matchStr)
{
bool isMark = Regex.IsMatch(matchStr, openingBrackets);
return isMark;
}
//判断行尾是否是成对字符的开始字符
private bool MatchLineEndStr(string matchStr)
{
bool isMark = Regex.IsMatch(matchStr, openingBrackets);
return isMark;
}
private string moveLineLast(string str)
{
string originStr = str;
bool flag = true;
int maxWhileCount = 50;
int whileCount = 0;
while (flag)
{
if (whileCount >= maxWhileCount)
{
return originStr;
}
flag = CheckMove(ref str);
whileCount++;
}
return str;
}
#endregion
}
行首标点检测功能
于 2024-11-19 15:48:38 首次发布