前言
今天碰到一个需求,项目中有时候的Text的文本会出现标点符号在句首的情况。
需求是标点符号不能出现在句首,而且我们项目是自适应的,不同分辨率下Text的宽不同,这就导致了无论怎样修改文案,都可能会出现标点符号在句首的情况,所以要改进一下。
在网上搜到了一些解决方案的代码,放到项目里发现有问题没办法用,而且比较复杂有点难理解,所以我就研究了一下,写了一个比较简单的解决方案。
原理
暴力排序
首先我们要把字符串分割来看。
那么通常情况下,Text应该是这样排列的
相当于先获取到Text文本框的宽度,再获取到当前文本所占的宽(不同汉字的像素宽是不同的,所以没办法准确的获取一个汉字的宽)。
再进行判断,当放到某个字时文本的宽度超出了文本框的宽度,那么就说明这个字是要换行的。
再判断这个字是不是标点符号,是的话就把它和它前面的一个字拿到另一行。
就像这样
那么这样就简单地实现了句首标点符号的处理方法
注意
没有加空格的判断,所以要确保文本中不能出现空格;
文本框必须能获取到宽度;
如果使用自动布局组件的话,偶尔情况下可能当前帧的文本框宽度为0,需要延迟处理
但是这个代码现在还有个缺陷,那就是经过处理的文本有时候会长短不一,看起来有点丑
但是大部分情况下应该够用了
使用方法
通过Text组件调用
不知道我的方法性能开销大不大,本人是Unity新手,如果有改进的地方欢迎提出来!!
其实应该还有另外的解决方案,比如TextMeshPro,感兴趣的小伙伴可以研究一下。
代码
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 字符串标点符号格式化
/// </summary>
public static class StringPunctuationFormatting
{
static List<string> punctuations = new List<string> {
",", ",",
"!", "!",
"。", ".",
"?", "?",
"~",
"+", "-", "*", "/",
"《", "<",
"》", ">",
"、", @"\",
":", ":",
";", ";",
"“", "\'",
"”", "‘", "’",
};
static int MinFontSize = 30;
static int MaxFontSize = 40;
static IEnumerator FrameEnumerator(Text TextComponent)
{
yield return new WaitUntil(() => Alignment(TextComponent.transform) != 0);
PunctuationFormat(TextComponent);
//while (true)
//{
// float result = Alignment(TextComponent.transform);
// if (result != 0)
// {
// PunctuationFormat(TextComponent);
// yield break;
// }
// yield return null;
//}
}
///在对象或者父对象有自动布局组件的时候,会出现文本框宽度在下一帧才有具体值,因此要进行延迟处理
/// <summary>
/// 延迟执行标点符号处理
/// </summary>
public static void LateFramePunctuationFormat(this Text TextComponent)
{
TextComponent.StartCoroutine(FrameEnumerator(TextComponent));
}
/// <summary>
/// 标点符号格式化
/// </summary>
/// <param name="TextComponent">文本组件</param>
public static void PunctuationFormat(this Text TextComponent)
{
//Debug.LogError("执行处理");
string text = TextComponent.text;
if (text == string.Empty || text == "" || text.Length == 0)
{
Debug.LogError("字符串为空");
return;
}
//获取文本框宽度
float boundWidth = Alignment(TextComponent.transform);
//如果Text组件使用bestfit,那么会根据文本框宽度计算字体大小,通常情况下SetTextFontSize方法需要根据项目需求改写
if (TextComponent.resizeTextForBestFit)
TextComponent.fontSize = SetTextFontSize(text.Length, (int)boundWidth);
TextGenerator generator = new TextGenerator();
TextGenerationSettings settings = CopyFrom(TextComponent.GetGenerationSettings(TextComponent.rectTransform.rect.size));//获取文本框数据
List<string> charList = StringFormat(text);
List<string> stringList = new List<string>();
string str = string.Empty;
float width;
foreach (var item in charList)
{
str += item;//当前组合的字符
TextComponent.text = str;
width = generator.GetPreferredWidth(TextComponent.text, settings) / settings.scaleFactor;//当前文本宽度
if (width > boundWidth)//说明这次添加的字导致了换行
{
string line;//处理好的一行字
if (isPunctuation(item))//判断是否为标点
{
line = str.Substring(0, str.Length - 2);//将最后一个字拿给下一行
str = str.Substring(str.Length - 2, 2);
}
else
{
line = str.Substring(0, str.Length - 1);
str = str.Substring(str.Length - 1, 1);
}
//再次判断最后一个字是否为标点
lastOneIsPun(ref line, ref str);
stringList.Add(line);
}
//如果是最后一次循环且没超行,
//为了避免有和结尾一样的字时误以为结束,要判断内存地址是否相同
if (object.ReferenceEquals(item, charList.LastOrDefault()))
{
stringList.Add(str);
}
}
//以下处理单字不成行
if (stringList.Count > 1 && stringList[stringList.Count - 1].Length <= 3) //判断最后一行字数,如果是单字的话
{
Debug.LogError("单子不成行");
string newLine= stringList[stringList.Count - 2].Substring(0, stringList[stringList.Count - 2].Length - 1);
string x= stringList[stringList.Count - 2].Substring(stringList[stringList.Count - 2].Length - 1, 1);//上一行的最后一个字
stringList[stringList.Count - 2] = newLine;//删去一个字的新行
stringList[stringList.Count - 1]=stringList[stringList.Count - 1].Insert(1, x);//添加给新一行
}
string endstring = string.Empty;
for (int i = 0; i < stringList.Count; i++)
{
endstring += stringList[i];
}
//foreach (var item in stringList)
//{
// Debug.LogError(item);
// endstring += item;
//}
TextComponent.text = endstring;
}
/// <summary>
/// 判断最后一个字是否为标点
/// </summary>
/// <returns></returns>
static void lastOneIsPun(ref string line, ref string str)
{
if (isPunctuation(str[0].ToString()))//如果第一个字是标点
{
str = line.Substring(line.Length - 1, 1) + str;
line = line.Substring(0, line.Length - 1);
lastOneIsPun(ref line, ref str);
return;
}
str = "\n" + str;
}
static bool isPunctuation(string item)
{
foreach (var pun in punctuations)
{
if (item == pun)
return true;
}
return false;
}
/// <summary>
/// 获取文本框的宽
/// </summary>
/// <param name="transform"></param>
/// <returns>文本框宽度</returns>
static float Alignment(Transform transform)
{
RectTransform rectTransform = transform.GetComponent<RectTransform>();
return rectTransform.rect.width;
}
/// <summary>
/// 格式化字符串
/// </summary>
/// <param name="str"></param>
/// <returns>每个字符的列表</returns>
static List<string> StringFormat(string str)
{
List<string> strlist = new List<string>();
for (int i = 0; i < str.Length; i++)
{
strlist.Add(str.Substring(0, 1));
str = str.Substring(1);
i--;
}
return strlist;
}
/// <summary>
/// 设置字体大小,最小为30最大为40。以文本框宽400,字体40为标准来计算:每多2个字字号减小1,文本框宽度每增加80,每多两个字的基础上再多一个字字号才减1
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
static int SetTextFontSize(int length,int width)
{
int force = Mathf.Max(0, (width - 400) / 80);
int newSize = MaxFontSize - (length - MaxFontSize) / (force+2);
return Mathf.Clamp(newSize, MinFontSize, MaxFontSize);
}
/// <summary>
/// 获取Text组件配置属性
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
static TextGenerationSettings CopyFrom(TextGenerationSettings o)
{
return new TextGenerationSettings
{
font = o.font,
color = o.color,
fontSize = o.fontSize,
lineSpacing = o.lineSpacing,
richText = o.richText,
scaleFactor = o.scaleFactor,
fontStyle = o.fontStyle,
textAnchor = o.textAnchor,
alignByGeometry = o.alignByGeometry,
resizeTextForBestFit = o.resizeTextForBestFit,
resizeTextMinSize = o.resizeTextMinSize,
resizeTextMaxSize = o.resizeTextMaxSize,
updateBounds = o.updateBounds,
verticalOverflow = o.verticalOverflow,
horizontalOverflow = o.horizontalOverflow,
generationExtents = o.generationExtents,
pivot = o.pivot,
generateOutOfBounds = o.generateOutOfBounds
};
}
}
示例//未更新
示例Demo文章来源:https://www.toymoban.com/news/detail-780202.html
参考文献
参考文献文章来源地址https://www.toymoban.com/news/detail-780202.html
到了这里,关于【Unity】Text组件标点符号句首优化(Text标点符号开头、标点符号换行)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!